图像通用特征的提取

来源:互联网 发布:红帽linux界面 编辑:程序博客网 时间:2024/09/21 08:57

主要包含了图像的灰度直方图、灰度图像的信息熵、圆形度……等35个图像通用特征的提取;

Character.h

#include <vector>#include <iterator>#include <numeric>#include <algorithm>#include <functional>using namespace std;// 存储目标物体的椭圆结构特征typedef struct _FitEllipse{float e;// 离心率float height;// 长轴长float width;// 短轴长float fit;// 拟合度float angle;// 椭圆倾角float length;// 椭圆周长float area;// 椭圆面积} FitEllipse;// 存储三个 double 类型的数组typedef struct _Scalar{public:inline _Scalar Scalar(double val0 = 0, double val1 = 0, double val2 = 0){val[0] = val0;val[1] = val1;val[2] = val2;}public:double val[3];} Scalar;class ImageProcess{public:ImageProcess();virtual ~ImageProcess();public:// load imageIplImage* loadImage(const char* fileName, unsigned colorMode = 1);// binaryzation of imageIplImage* binaryImg(IplImage* img, unsigned threshold, int thresholdType);public:// get binary imageIplImage* getBinaryImg() { return m_binaryImg; }private:IplImage* m_binaryImg;// binary image};class Character : public ImageProcess{public:Character();~Character();public:// 查找轮廓CvSeq* findImgContours(IplImage* img, CvMemStorage* storage);// 计算目标区域的均值和方差 void calAvgSdv(IplImage* img, CvSeq* seq, Scalar *ave = NULL, Scalar *sdv = NULL);// 计算直方图template<typename _T>void calHist(IplImage* img, CvSeq* seq, _T hist[]);// 计算概率最大的灰度值int calHistValue(IplImage* img, CvSeq* seq);// 计算图像的熵值double calEntropy(IplImage* img, CvSeq* seq);// 计算图像的椭圆拟合度FitEllipse calEllipseCharater(CvSeq* seq);// 计算矩形度double calRectFit(CvSeq* seq);// 计算紧密度double calHullFit(CvSeq* seq, CvMemStorage* storage = 0);// 计算目标区域面积int calROIArea(IplImage* img, CvSeq* seq);// 计算重心CvPoint calBaryCentre(IplImage* img, CvSeq* seq);// 计算形状参数(紧凑性)double calCompactness(CvSeq* seq);// 计算偏心率double calEccentricity(CvSeq* seq);// 计算圆形性double calCircularity(IplImage* img, CvSeq* seq);// 计算 7个 hu 矩CvHuMoments calHuMoments(CvSeq* seq);// 获取面积最大的轮廓CvSeq* getMaxAreaContour(CvSeq* seq);private:CvSeq* m_seq;FitEllipse m_ellipse;int m_nArea;int m_nX;int m_nY;};

characer.cpp

#include "stdafx.h"#include "Character.h"ImageProcess::ImageProcess():m_binaryImg(NULL){}ImageProcess::~ImageProcess(){if (m_binaryImg != NULL){cvReleaseImage(&m_binaryImg);m_binaryImg = NULL;}}IplImage* ImageProcess::loadImage(const char* fileName, unsigned colorMode /* = 1 */){return cvLoadImage(fileName, colorMode);}IplImage* ImageProcess::binaryImg(IplImage* img, unsigned threshold, int thresholdType){#ifdef _DEBUGassert(img != NULL);assert((img->nChannels == 1) || (img->nChannels == 3));assert((threshold >= 0) && (threshold <= 255));#endifm_binaryImg = cvCreateImage(cvGetSize(img), img->depth, 1);if (img->nChannels == 1){cvThreshold(img, m_binaryImg, threshold, 255, thresholdType);}else{IplImage* rImg = cvCreateImage(cvGetSize(img), img->depth, 1);cvSplit(img, NULL, NULL, rImg, NULL);cvThreshold(rImg, m_binaryImg, threshold, 255, thresholdType);if (rImg != NULL){cvReleaseImage(&rImg);}}IplConvKernel* element = cvCreateStructuringElementEx(5, 5, 2, 2, CV_SHAPE_ELLIPSE);cvSmooth(m_binaryImg, m_binaryImg, CV_MEDIAN);cvErode(m_binaryImg, m_binaryImg, element, 1);cvDilate(m_binaryImg, m_binaryImg, element, 1);cvReleaseStructuringElement(&element);return m_binaryImg;}Character::Character(): m_nArea(0){}Character::~Character(){}CvSeq* Character::getMaxAreaContour(CvSeq* seq){#ifdef _DEBUGassert(seq != 0);#endifCvSeq* maxSeq = 0;for (CvSeq* c = seq; c != NULL; c = c->h_next){float area = fabs(cvContourArea(c, CV_WHOLE_SEQ));// get area of contoursif (m_nArea < area){maxSeq = c;}}return maxSeq;}// 查找图像轮廓CvSeq* Character::findImgContours(IplImage* img, CvMemStorage* storage){if (img->nChannels != 1)return NULL;CvSeq *seq = 0;cvFindContours(img, storage, &seq, sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);// 检索轮廓for (; seq != 0; seq = seq->h_next){m_seq = getMaxAreaContour(seq);}return m_seq;}// 计算目标区域的均值和方差void Character::calAvgSdv(IplImage* img, CvSeq* seq, Scalar *ave, Scalar *sdv){IplImage* bitImg = getBinaryImg();CvRect rect = { 0 };for (; seq != 0; seq = seq->h_next){// 画出二值图像的轮廓cvDrawContours(bitImg, seq, cvScalarAll(255), cvScalarAll(255),-1, CV_FILLED, 8);rect = cvBoundingRect(seq, 0);}if (img->nChannels == 1)// 如果是单通道图像{vector<double> vec;for (int i = rect.x; i < rect.x + rect.width; ++i){for (int j = rect.y; j < rect.y + rect.height; ++j){CvScalar s = cvGet2D(bitImg, j, i);if (s.val[0] == 255){s = cvGet2D(img, j, i);vec.push_back(s.val[0]);}}} // end for i// 计算均值if (ave != NULL){if (!vec.empty()){ave->val[0] = (double)(accumulate(vec.begin(), vec.end(), 0))/ vec.size();}}// 计算方差if (sdv != NULL){if (! vec.empty()){double sum = 0.0;for_each(vec.begin(), vec.end(), [&](const double d){sum += pow((d - ave->val[0]), 2);});sdv->val[0] = sqrt(sum / vec.size());}}}// end if img->nChannel == 1if (img->nChannels == 3)  // 如果图像为 3 通道图像{vector<double> vec[3];for (int i = 0; i < rect.x + rect.width; ++i){for (int j = 0; j < rect.y + rect.height; ++j){CvScalar s = cvGet2D(bitImg, j, i);if (s.val[0] == 255){s = cvGet2D(img, j, i);vec[0].push_back(s.val[0]);vec[1].push_back(s.val[1]);vec[2].push_back(s.val[2]);}}}// end for i// 计算均值if (ave != NULL){for (int i = 0; i < 3; ++i){if (! vec[i].empty()){ave->val[i] = (double)(accumulate(vec[i].begin(), vec[i].end(), 0))/ vec[i].size();}}}// end aveif (sdv != NULL){for (int i = 0; i < 3; ++i){if (!vec[i].empty()){double sum = 0.0;for_each(vec[i].begin(), vec[i].end(), [&](const double d){sum += pow(d - ave->val[i], 2);});sdv->val[i] = sqrt(sum / vec->size());}}}// end if sdv}// end if img->nChannels == 3}// 计算直方图template<typename _T>void Character::calHist(IplImage* img, CvSeq* seq, _T hist[]){IplImage* grayImg = NULL;IplImage* bitImg = getBinaryImg();grayImg = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);if (img->nChannels == 3)cvCvtColor(img, grayImg, CV_RGB2GRAY);elsecvCopy(img, grayImg, NULL);CvRect rect = { 0 };for (; seq != 0; seq = seq->h_next){cvDrawContours(bitImg, seq, cvScalarAll(255), cvScalarAll(255),-1, CV_FILLED, 8);rect = cvBoundingRect(seq, 0);}for (int i = rect.x; i < rect.x + rect.width; ++i){for (int j = rect.y; j < rect.y + rect.height; ++j){CvScalar s = cvGet2D(bitImg, j, i);if (s.val[0] == 255){s = cvGet2D(grayImg, j, i);int val = s.val[0];++hist[val];}}}// 释放内存cvReleaseImage(&grayImg);}// 利用直方图,统计出出现频率最高的灰度值int Character::calHistValue(IplImage* img, CvSeq* seq){int hist[256] = { 0 };calHist(img, seq, hist);int maxVal = 0;int grayVal = 0;for (int i = 0; i < 256; ++i){if (maxVal < hist[i]){maxVal = hist[i];grayVal = i;// 求出出现概率最大的灰度值}}return grayVal;}// 计算图像的熵值double Character::calEntropy(IplImage* img, CvSeq* seq){// 计算直方图double hist[256] = { 0.0 };calHist(img, seq, hist);int total = 0;for (int i = 0; i < 256; ++i){total += hist[i];}// 计算每个灰度值的概率double temp[256] = { 0.0 };for (int i = 0; i < 256; ++i){temp[i] = hist[i] / total;}// 计算信息熵double entropy = 0.0;for (int i = 0; i < 256; ++i){if (temp[i] == 0.0){entropy = entropy;}else{entropy -= temp[i] * (log(temp[i]) / log(2.0));}}return entropy;}// 提取椭圆特征FitEllipse Character::calEllipseCharater(CvSeq* seq){CvBox2D box = { 0 };double area = 0;for (; seq != 0; seq = seq->h_next){// 计算拟合椭圆box = cvFitEllipse2(seq);area = fabs(cvContourArea(seq, CV_WHOLE_SEQ));}box.angle = 90 - box.angle;m_ellipse.angle = box.angle;// 倾角float height = box.size.height;float width = box.size.width;// 取较大的值为椭圆的长轴长,较小的值为短轴长if (height > width){m_ellipse.height = height;m_ellipse.width = width;}else{m_ellipse.height = width;m_ellipse.width = height;}float a = 0, b = 0;a = m_ellipse.height;// 长轴长b = m_ellipse.width;// 短轴长// 周长float l = 3.14f * b + 2 * (a - b);m_ellipse.length = l;float ellArea = 3.14f * a * b / 4;// 椭圆面积m_ellipse.area = ellArea;// 椭圆拟合度float fit = area / ellArea;m_ellipse.fit = fit;// 离心率float c = sqrt((a * a) - (b * b));float e = c / a;m_ellipse.e = e;return m_ellipse;}// 计算矩形度double Character::calRectFit(CvSeq* seq){CvBox2D rect;double area = 0.0;for (; seq != 0; seq = seq->h_next){rect = cvMinAreaRect2(seq);// 最小拟合矩形area = fabs(cvContourArea(seq, CV_WHOLE_SEQ));}double rectArea = rect.size.height * rect.size.width;double fit = area / rectArea;// 矩形度return fit;}// 计算凸包double Character::calHullFit(CvSeq* seq, CvMemStorage* storage){CvSeq* hull = 0;double hullArea = 0.0, area = 0.0;for (; seq != 0; seq = seq->h_next){// 最内外接凸多边形,多边形逼近//hull = cvApproxPoly(seq, sizeof(CvContour), storage, CV_POLY_APPROX_DP, 3, 1);// 凸包,最小外接凸多边形hull = cvConvexHull2(seq, 0, CV_CLOCKWISE, 1);hullArea = fabs(cvContourArea(hull, CV_WHOLE_SEQ));area = fabs(cvContourArea(seq, CV_WHOLE_SEQ));}double fit = area / hullArea;return fit;}// 计算目标区域面积int Character::calROIArea(IplImage* img,CvSeq* seq){if (img == NULL || img->nChannels != 1)return 0;CvRect rect = { 0 };for (; seq != 0; seq = seq->h_next){cvDrawContours(img, seq, cvScalarAll(255), cvScalarAll(255), -1, CV_FILLED, 8);rect = cvBoundingRect(seq, 0);}for (int i = rect.x; i < rect.x + rect.width; ++i){for (int j = rect.y; j < rect.y + rect.height; ++j){CvScalar s = cvGet2D(img, j, i);if (s.val[0] == 255){++m_nArea;}}}return m_nArea;}// 计算图像重心CvPoint Character::calBaryCentre(IplImage* img,CvSeq* seq){if (img == NULL || img->nChannels != 1)return cvPoint(0, 0);double m00 = 0.0, m10 = 0.0, m01 = 0.0;for (; seq != 0; seq = seq->h_next){CvMoments moment;cvMoments(img, &moment, 1);m00 = cvGetSpatialMoment(&moment, 0, 0);m10 = cvGetSpatialMoment(&moment, 1, 0);m01 = cvGetSpatialMoment(&moment, 0, 1);}// 图像重心坐标CvPoint pt = { 0 };pt.x =(int)(m10 / m00);pt.y =(int)(m01 / m00);return pt;}// 计算形状参数(紧密度)double Character::calCompactness(CvSeq* seq){double area = 0, length = 0;for (; seq != 0; seq = seq->h_next){area = fabs(cvContourArea(seq, CV_WHOLE_SEQ));length = cvArcLength(seq, CV_WHOLE_SEQ);}double f = (length * length) / (4 * 3.14 * area);return f;}// 计算偏心率double Character::calEccentricity(CvSeq* seq){CvBox2D rect = { 0 };for (; seq != 0; seq = seq->h_next){rect = cvMinAreaRect2(seq);// 最小外接矩形}double f = 0.0;(rect.size.height > rect.size.width)? (f = rect.size.height / rect.size.width): (f = rect.size.width / rect.size.height);return f;}// 计算圆形性double Character::calCircularity(IplImage* img, CvSeq* seq){if (img == NULL || img->nChannels != 1)return 0.0;double m00 = 0.0, m10 = 0.0, m01 = 0.0;// 以下代码计算图像的圆形性float UR = 0.f;// 从区域重心到边界点的平均距离float PR = 0.f;// 从区域重心到边界点的距离的方差for (; seq != 0; seq = seq->h_next){CvMoments moment;cvMoments(img, &moment, 1);m00 = cvGetSpatialMoment(&moment, 0, 0);m10 = cvGetSpatialMoment(&moment, 1, 0);m01 = cvGetSpatialMoment(&moment, 0, 1);// 图像重心坐标int x = (int)(m10 / m00);int y = (int)(m01 / m00);float sum = 0;int count = seq->total;CvPoint* pt;for (int i = 0; i < count; ++i){pt = (CvPoint*)cvGetSeqElem(seq, i);sum += sqrt(powf(pt->x - x, 2) + powf(pt->y - y, 2));}UR = sum / count;float tmp = 0.f;sum = 0;for (int i = 0; i < count; ++i){pt = (CvPoint*)cvGetSeqElem(seq, i);tmp = sqrt(powf(pt->x - x, 2) + powf(pt->y - y, 2));sum += powf(tmp - UR, 2);}PR = sum / count;}// 计算圆形性double circularity = UR / PR;return circularity;}// 计算 7 个 hu 不变矩CvHuMoments Character::calHuMoments(CvSeq* seq){CvHuMoments huMoments;for (; seq != 0; seq = seq->h_next){// 提取7个 hu 不变矩CvMoments moments;cvMoments(seq, &moments, 1);cvGetHuMoments(&moments, &huMoments);}return huMoments;}



0 0
原创粉丝点击