導言:本系列博客目的在於可以在vs快速上手opencv,理論知識涉及較少,你們有興趣能夠查閱其餘博客深刻了解相關的理論知識,本博客後續也會對圖像方向的理論進一步分析,敬請期待:)html
上篇傳送:http://www.cnblogs.com/always-chang/p/6170727.htmlwindows
學習思惟導圖:數組
主要函數介紹:網絡
1)cvFindContours數據結構
函數功能:對圖像進行輪廓檢測,這個函數將生成一條鏈表以保存檢測出的各個輪廓信息,並傳出指向這條鏈表表頭的指針。函數
函數原型:學習
int cvFindContours(spa
CvArr* image,.net
CvMemStorage* storage,3d
CvSeq** first_contour,
int header_size=sizeof(CvContour),
int mode=CV_RETR_LIST,
int method=CV_CHAIN_APPROX_SIMPLE,
CvPoint offset=cvPoint(0,0)
);
函數說明:
第一個參數表示輸入圖像,必須爲一個8位的二值圖像。
第二參數表示存儲輪廓的容器。爲CvMemStorage類型,定義在OpenCV的\core\types_c.h中。
第三個參數爲輸出參數,這個參數將指向用來存儲輪廓信息的鏈表表頭。
第四個參數表示存儲輪廓鏈表的表頭大小,當第六個參數傳入CV_CHAIN_CODE時,要設置成sizeof(CvChain),其它狀況統一設置成sizeof(CvContour)。
第五個參數爲輪廓檢測的模式,有以下取值:
CV_RETR_EXTERNAL:只檢索最外面的輪廓;
CV_RETR_LIST:檢索全部的輪廓,並將其保存到一條鏈表當中;
CV_RETR_CCOMP:檢索全部的輪廓,並將他們組織爲兩層:頂層是各部分的外部邊界,第二層是空洞的邊界;
CV_RETR_TREE:檢索全部的輪廓,並重構嵌套輪廓的整個層次。
第六個參數用來表示輪廓邊緣的近似方法的,經常使用值以下所示:
CV_CHAIN_CODE:以Freeman鏈碼的方式輸出輪廓,全部其餘方法輸出多邊形(頂點的序列)。
CV_CHAIN_APPROX_SIMPLE:壓縮水平的、垂直的和斜的部分,也就是,函數只保留他們的終點部分。
第七個參數表示偏移量,好比你要從圖像的(100, 0)開始進行輪廓檢測,那麼就傳入(100, 0)。
使用cvFindContours函數能檢測出圖像的輪廓,將輪廓繪製出來則須要另外一函數——cvDrawContours來配合了。下面介紹cvDrawContours函數。
2)cvDrawContours
函數功能:在圖像上繪製外部和內部輪廓
函數原型:
void cvDrawContours(
CvArr *img,
CvSeq* contour,
CvScalar external_color,
CvScalar hole_color,
int max_level,
int thickness=1,
int line_type=8,
CvPoint offset=cvPoint(0,0)
);
第一個參數表示輸入圖像,函數將在這張圖像上繪製輪廓。
第二個參數表示指向輪廓鏈表的指針。
第三個參數和第四個參數表示顏色,繪製時會根據輪廓的層次來交替使用這二種顏色。
第五個參數表示繪製輪廓的最大層數,若是是0,只繪製contour;若是是1,追加繪製和contour同層的全部輪廓;若是是2,追加繪製比contour低一層的輪廓,以此類推;若是值是負值,則函數並不繪製contour後的輪廓,可是將畫出其子輪廓,一直到abs(max_level) - 1層。
第六個參數表示輪廓線的寬度,若是爲CV_FILLED則會填充輪廓內部。
第七個參數表示輪廓線的類型。
第八個參數表示偏移量,若是傳入(10,20),那繪製將從圖像的(10,20)處開始。
1 #include <opencv2/opencv.hpp> 2 using namespace std; 3 #pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"") 4 IplImage *g_pGrayImage = NULL; 5 const char *pstrWindowsBinaryTitle = "二值圖"; 6 const char *pstrWindowsOutLineTitle = "輪廓圖"; 7 CvSeq *g_pcvSeq = NULL; 8 9 void on_trackbar(int pos) 10 { 11 // 轉爲二值圖 12 IplImage *pBinaryImage = cvCreateImage(cvGetSize(g_pGrayImage), IPL_DEPTH_8U, 1); 13 cvThreshold(g_pGrayImage, pBinaryImage, pos, 255, CV_THRESH_BINARY); 14 // 顯示二值圖 15 cvShowImage(pstrWindowsBinaryTitle, pBinaryImage); 16 17 CvMemStorage* cvMStorage = cvCreateMemStorage(); 18 // 檢索輪廓並返回檢測到的輪廓的個數 19 cvFindContours(pBinaryImage, cvMStorage, &g_pcvSeq); 20 21 IplImage *pOutlineImage = cvCreateImage(cvGetSize(g_pGrayImage), IPL_DEPTH_8U, 3); 22 int _levels = 5; 23 cvZero(pOutlineImage); 24 cvDrawContours(pOutlineImage, g_pcvSeq, CV_RGB(255, 0, 0), CV_RGB(0, 255, 0), _levels); 25 cvShowImage(pstrWindowsOutLineTitle, pOutlineImage); 26 27 cvReleaseMemStorage(&cvMStorage); 28 cvReleaseImage(&pBinaryImage); 29 cvReleaseImage(&pOutlineImage); 30 } 31 32 int main(int argc, char** argv) 33 { 34 const char *pstrWindowsSrcTitle = "原圖"; 35 const char *pstrWindowsToolBarName = "二值化"; 36 37 // 從文件中加載原圖 38 IplImage *pSrcImage = cvLoadImage("01.jpg", CV_LOAD_IMAGE_UNCHANGED); 39 // 顯示原圖 40 cvNamedWindow(pstrWindowsSrcTitle, CV_WINDOW_AUTOSIZE); 41 cvShowImage(pstrWindowsSrcTitle, pSrcImage); 42 43 // 轉爲灰度圖 44 g_pGrayImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 1); 45 cvCvtColor(pSrcImage, g_pGrayImage, CV_BGR2GRAY); 46 47 // 建立二值圖和輪廓圖窗口 48 cvNamedWindow(pstrWindowsBinaryTitle, CV_WINDOW_AUTOSIZE); 49 cvNamedWindow(pstrWindowsOutLineTitle, CV_WINDOW_AUTOSIZE); 50 51 52 // 滑動條 53 int nThreshold = 0; 54 cvCreateTrackbar(pstrWindowsToolBarName, pstrWindowsBinaryTitle, &nThreshold, 254, on_trackbar); 55 56 on_trackbar(1); 57 58 cvWaitKey(0); 59 60 cvDestroyWindow(pstrWindowsSrcTitle); 61 cvDestroyWindow(pstrWindowsBinaryTitle); 62 cvDestroyWindow(pstrWindowsOutLineTitle); 63 cvReleaseImage(&pSrcImage); 64 cvReleaseImage(&g_pGrayImage); 65 return 0; 66 }
輸出:
六、鼠標繪圖
關鍵函數介紹
1)cvSetMouseCallback
函數功能:設置處理鼠標消息的回調函數
函數原型:
/* assign callback for mouse events */
CVAPI(void) cvSetMouseCallback(
const char* window_name,
CvMouseCallback on_mouse,
void* param CV_DEFAULT(NULL)
);
函數說明:
第一個參數表示窗口名稱。
第二個參數表示鼠標消息的消息處理函數。
第三個參數表示用戶定義傳入鼠標指定消息處理函數的參數。
2)CvMouseCallback
函數功能:鼠標消息的回調函數
函數原型:
typedef void (CV_CDECL *CvMouseCallback )(int event, int x, int y, int flags, void* param);
函數說明:
第一個參數表示鼠標消息類型,取值以下:
enum
{
CV_EVENT_MOUSEMOVE =0,
CV_EVENT_LBUTTONDOWN =1,
CV_EVENT_RBUTTONDOWN =2,
CV_EVENT_MBUTTONDOWN =3,
CV_EVENT_LBUTTONUP =4,
CV_EVENT_RBUTTONUP =5,
CV_EVENT_MBUTTONUP =6,
CV_EVENT_LBUTTONDBLCLK =7,
CV_EVENT_RBUTTONDBLCLK =8,
CV_EVENT_MBUTTONDBLCLK =9
};
第二,三個參數表示鼠標的座標。
第四個參數表示附加事件,取值以下:
enum
{
CV_EVENT_FLAG_LBUTTON =1,
CV_EVENT_FLAG_RBUTTON =2,
CV_EVENT_FLAG_MBUTTON =4,
CV_EVENT_FLAG_CTRLKEY =8,
CV_EVENT_FLAG_SHIFTKEY =16,
CV_EVENT_FLAG_ALTKEY =32
};
第五個參數即設置cvSetMouseCallback()中將接收到的參數。
1 #include <opencv2/opencv.hpp> 2 using namespace std; 3 #pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"") 4 const char *pstrWindowsMouseDrawTitle = "鼠標繪圖"; 5 // 鼠標消息的回調函數 6 void on_mouse(int event, int x, int y, int flags, void* param) 7 { 8 static bool s_bMouseLButtonDown = false; 9 static CvPoint s_cvPrePoint = cvPoint(0, 0); 10 11 switch (event) 12 { 13 case CV_EVENT_LBUTTONDOWN: 14 s_bMouseLButtonDown = true; 15 s_cvPrePoint = cvPoint(x, y); 16 break; 17 18 case CV_EVENT_LBUTTONUP: 19 s_bMouseLButtonDown = false; 20 break; 21 22 case CV_EVENT_MOUSEMOVE: 23 if (s_bMouseLButtonDown) 24 { 25 CvPoint cvCurrPoint = cvPoint(x, y); 26 cvLine((IplImage*)param, s_cvPrePoint, cvCurrPoint, CV_RGB(0, 0, 20), 3); 27 s_cvPrePoint = cvCurrPoint; 28 cvShowImage(pstrWindowsMouseDrawTitle, (IplImage*)param); 29 } 30 break; 31 } 32 } 33 int main() 34 { 35 const int MAX_WIDTH = 500, MAX_HEIGHT = 400; 36 const char *pstrSaveImageName = "Draw.jpg"; 37 38 IplImage *pSrcImage = cvCreateImage(cvSize(MAX_WIDTH, MAX_HEIGHT), IPL_DEPTH_8U, 3); 39 cvSet(pSrcImage, CV_RGB(255, 255, 255)); //能夠用cvSet()將圖像填充成白色 40 cvNamedWindow(pstrWindowsMouseDrawTitle, CV_WINDOW_AUTOSIZE); 41 cvShowImage(pstrWindowsMouseDrawTitle, pSrcImage); 42 43 cvSetMouseCallback(pstrWindowsMouseDrawTitle, on_mouse, (void*)pSrcImage); 44 45 int c; 46 do{ 47 c = cvWaitKey(0); 48 switch ((char)c) 49 { 50 case 'r'://r重畫 51 cvSet(pSrcImage, CV_RGB(255, 255, 255)); 52 cvShowImage(pstrWindowsMouseDrawTitle, pSrcImage); 53 break; 54 55 case 's'://s保存圖像 56 cvSaveImage(pstrSaveImageName, pSrcImage); 57 break; 58 } 59 } while (c > 0 && c != 27); 60 61 cvDestroyWindow(pstrWindowsMouseDrawTitle); 62 cvReleaseImage(&pSrcImage); 63 return 0; 64 }
畫的太醜,就不貼了。。。
七、人臉檢測
使用人臉的Haar特徵分類器很是之簡單,直接使用cvHaarDetectObjects。下面來看看這個函數的介紹:
函數功能:檢測圖像中的目錄
函數原型:
CVAPI(CvSeq*) cvHaarDetectObjects(
const CvArr* image,
CvHaarClassifierCascade* cascade,
CvMemStorage* storage,
double scale_factor CV_DEFAULT(1.1),
int min_neighbors CV_DEFAULT(3),
int flags CV_DEFAULT(0),
CvSize min_size CV_DEFAULT(cvSize(0,0)),
CvSize max_size CV_DEFAULT(cvSize(0,0))
);
函數說明:
第一個參數表示輸入圖像,儘可能使用灰度圖以加快檢測速度。
第二個參數表示Haar特徵分類器,能夠用cvLoad()函數來從磁盤中加載xml文件做爲Haar特徵分類器。
第三個參數爲CvMemStorage類型,你們應該很熟悉這個CvMemStorage類型了。
第四個參數表示在先後兩次相繼的掃描中,搜索窗口的比例係數。默認爲1.1即每次搜索窗口依次擴大10%
第五個參數表示構成檢測目標的相鄰矩形的最小個數(默認爲3個)。若是組成檢測目標的小矩形的個數和小於 min_neighbors - 1 都會被排除。若是min_neighbors 爲 0, 則函數不作任何操做就返回全部的被檢候選矩形框,這種設定值通常用在用戶自定義對檢測結果的組合程序上。
第六個參數要麼使用默認值,要麼使用CV_HAAR_DO_CANNY_PRUNING,若是設置爲CV_HAAR_DO_CANNY_PRUNING,那麼函數將會使用Canny邊緣檢測來排除邊緣過多或過少的區域,所以這些區域一般不會是人臉所在區域。
第七個,第八個參數表示檢測窗口的最小值和最大值,通常設置爲默認便可。
函數返回值:
函數將返回CvSeq對象,該對象包含一系列CvRect表示檢測到的人臉矩形。
#include <opencv2/opencv.hpp> #include <cstdio> #include <cstdlib> #include <Windows.h> using namespace std; int main() { // 加載Haar特徵檢測分類器 // haarcascade_frontalface_alt.xml系OpenCV自帶的分類器 下面是我機器上的文件路徑 const char *pstrCascadeFileName = "E:\\opencv\\opencv\\data\\haarcascades\\haarcascade_frontalface_alt.xml"; CvHaarClassifierCascade *pHaarCascade = NULL; pHaarCascade = (CvHaarClassifierCascade*)cvLoad(pstrCascadeFileName); // 載入圖像 const char *pstrImageName = "cyh.jpg"; IplImage *pSrcImage = cvLoadImage(pstrImageName, CV_LOAD_IMAGE_UNCHANGED); IplImage *pGrayImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 1); cvCvtColor(pSrcImage, pGrayImage, CV_BGR2GRAY); // 人臉識別與標記 if (pHaarCascade != NULL) { CvScalar FaceCirclecolors[] = { { { 0, 0, 255 } }, { { 0, 128, 255 } }, { { 0, 255, 255 } }, { { 0, 255, 0 } }, { { 255, 128, 0 } }, { { 255, 255, 0 } }, { { 255, 0, 0 } }, { { 255, 0, 255 } } }; CvMemStorage *pcvMStorage = cvCreateMemStorage(0); cvClearMemStorage(pcvMStorage); // 識別 DWORD dwTimeBegin, dwTimeEnd; dwTimeBegin = GetTickCount(); CvSeq *pcvSeqFaces = cvHaarDetectObjects(pGrayImage, pHaarCascade, pcvMStorage); dwTimeEnd = GetTickCount(); printf("人臉個數: %d 識別用時: %d ms\n", pcvSeqFaces->total, dwTimeEnd - dwTimeBegin); // 標記 for (int i = 0; i < pcvSeqFaces->total; i++) { CvRect* r = (CvRect*)cvGetSeqElem(pcvSeqFaces, i); CvPoint center; int radius; center.x = cvRound((r->x + r->width * 0.5)); center.y = cvRound((r->y + r->height * 0.5)); radius = cvRound((r->width + r->height) * 0.25); cvCircle(pSrcImage, center, radius, FaceCirclecolors[i % 8], 2); } cvReleaseMemStorage(&pcvMStorage); } const char *pstrWindowsTitle = "人臉識別 "; cvNamedWindow(pstrWindowsTitle, CV_WINDOW_AUTOSIZE); cvShowImage(pstrWindowsTitle, pSrcImage); cvWaitKey(0); cvDestroyWindow(pstrWindowsTitle); cvReleaseImage(&pSrcImage); cvReleaseImage(&pGrayImage); return 0; }
輸出:
無遮擋背景乾淨:
三我的也能夠:
有遮擋就不行了,與商業化的軟件仍是有很大差異的。。
八、灰度直方圖
主要函數介紹:
1)cvCreateHist
函數功能:建立直方圖
函數原型:
CVAPI(CvHistogram*) cvCreateHist( // Creates new histogram
int dims,
int* sizes,
int type,
float** ranges CV_DEFAULT(NULL),
int uniform CV_DEFAULT(1)
);
參數說明:
第一個參數表示直方圖維數,灰度圖爲1,彩色圖爲3。
第二個參數表示直方圖維數的數目,其實就是sizes數組的維數。
第三個參數表示直方圖維數尺寸的數組。
第四個參數表示直方圖類型,爲CV_HIST_ARRAY表示直方圖數據表示爲多維密集數組,爲CV_HIST_TREE表示直方圖數據表示爲多維稀疏數組。
第五個參數表示歸一化標識,其原理有點複雜。一般使用默認值便可。
函數說明:
直方圖的數據結構以下所示:
typedef struct CvHistogram
{
int type;
CvArr* bins;
float thresh[CV_MAX_DIM][2]; /* For uniform histograms. */
float** thresh2; /* For non-uniform histograms. */
CvMatND mat; /* Embedded matrix header for array histograms. */
}CvHistogram;
2)cvCalcHist
函數功能:根據圖像計算直方圖
函數原型:
void cvCalcHist(
IplImage** image,
CvHistogram* hist,
int accumulate CV_DEFAULT(0),
const CvArr* mask CV_DEFAULT(NULL)
)
參數說明:
第一個參數表示輸入圖像。
第二個參數表示輸出的直方圖指針。
第三個參數操做mask, 肯定輸入圖像的哪一個象素被計數。
第四個參數表示累計標識。若是設置,則直方圖在開始時不被清零。這個特徵保證能夠爲多個圖像計算一個單獨的直方圖,或者在線更新直方圖。
函數說明:
這是個inline函數,函數內部會直接調用cvCalcArrHist( (CvArr**)image, hist, accumulate, mask );
1 #include <opencv2/opencv.hpp> 2 #include <opencv2/legacy/compat.hpp> 3 using namespace std; 4 #pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"") 5 6 void FillWhite(IplImage *pImage) 7 { 8 cvRectangle(pImage, cvPoint(0, 0), cvPoint(pImage->width, pImage->height), CV_RGB(255, 255, 255), CV_FILLED); 9 } 10 // 建立灰度圖像的直方圖 11 CvHistogram* CreateGrayImageHist(IplImage **ppImage) 12 { 13 int nHistSize = 256; 14 float fRange[] = { 0, 255 }; //灰度級的範圍 15 float *pfRanges[] = { fRange }; 16 CvHistogram *pcvHistogram = cvCreateHist(1, &nHistSize, CV_HIST_ARRAY, pfRanges); 17 cvCalcHist(ppImage, pcvHistogram); 18 return pcvHistogram; 19 } 20 // 根據直方圖建立直方圖圖像 21 IplImage* CreateHisogramImage(int nImageWidth, int nScale, int nImageHeight, CvHistogram *pcvHistogram) 22 { 23 IplImage *pHistImage = cvCreateImage(cvSize(nImageWidth * nScale, nImageHeight), IPL_DEPTH_8U, 1); 24 FillWhite(pHistImage); 25 26 //統計直方圖中的最大直方塊 27 float fMaxHistValue = 0; 28 cvGetMinMaxHistValue(pcvHistogram, NULL, &fMaxHistValue, NULL, NULL); 29 30 //分別將每一個直方塊的值繪製到圖中 31 int i; 32 for (i = 0; i < nImageWidth; i++) 33 { 34 float fHistValue = cvQueryHistValue_1D(pcvHistogram, i); //像素爲i的直方塊大小 35 int nRealHeight = cvRound((fHistValue / fMaxHistValue) * nImageHeight); //要繪製的高度 36 cvRectangle(pHistImage, 37 cvPoint(i * nScale, nImageHeight - 1), 38 cvPoint((i + 1) * nScale - 1, nImageHeight - nRealHeight), 39 cvScalar(i, 0, 0, 0), 40 CV_FILLED 41 ); 42 } 43 return pHistImage; 44 } 45 int main(int argc, char** argv) 46 { 47 const char *pstrWindowsSrcTitle = "原圖"; 48 const char *pstrWindowsGrayTitle = "灰度圖"; 49 const char *pstrWindowsHistTitle = "直方圖"; 50 51 // 從文件中加載原圖 52 IplImage *pSrcImage = cvLoadImage("cyh.jpg", CV_LOAD_IMAGE_UNCHANGED); 53 IplImage *pGrayImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 1); 54 // 灰度圖 55 cvCvtColor(pSrcImage, pGrayImage, CV_BGR2GRAY); 56 57 // 灰度直方圖 58 CvHistogram *pcvHistogram = CreateGrayImageHist(&pGrayImage); 59 60 // 建立直方圖圖像 61 int nHistImageWidth = 255; 62 int nHistImageHeight = 150; //直方圖圖像高度 63 int nScale = 2; 64 IplImage *pHistImage = CreateHisogramImage(nHistImageWidth, nScale, nHistImageHeight, pcvHistogram); 65 66 // 顯示 67 cvNamedWindow(pstrWindowsSrcTitle, CV_WINDOW_AUTOSIZE); 68 cvNamedWindow(pstrWindowsGrayTitle, CV_WINDOW_AUTOSIZE); 69 cvNamedWindow(pstrWindowsHistTitle, CV_WINDOW_AUTOSIZE); 70 cvShowImage(pstrWindowsSrcTitle, pSrcImage); 71 cvShowImage(pstrWindowsGrayTitle, pGrayImage); 72 cvShowImage(pstrWindowsHistTitle, pHistImage); 73 74 cvWaitKey(0); 75 76 cvReleaseHist(&pcvHistogram); 77 78 cvDestroyWindow(pstrWindowsSrcTitle); 79 cvDestroyWindow(pstrWindowsGrayTitle); 80 cvDestroyWindow(pstrWindowsHistTitle); 81 cvReleaseImage(&pSrcImage); 82 cvReleaseImage(&pGrayImage); 83 cvReleaseImage(&pHistImage); 84 return 0; 85 }
輸出:
主要函數介紹:
1)cvEqualizeHist
函數功能:直方圖均衡化,該函數能歸一化圖像亮度和加強對比度
函數原型:
/* equalizes histogram of 8-bit single-channel image */
CVAPI(void) cvEqualizeHist( const CvArr* src, CvArr* dst );
第一個參數表示輸入圖像,必須爲灰度圖(8位,單通道圖)。
第二個參數表示輸出圖像
函數說明:
該函數採用以下法則對輸入圖像進行直方圖均衡化:
1:計算輸入圖像的直方圖H。
2:直方圖歸一化,所以直方塊和爲255。
3:計算直方圖積分,H'(i) = Sum(H(j)) (0<=j<=i)。
4:採用H'做爲查詢表:dst(x, y) = H'(src(x, y))進行圖像變換。
1 #include <opencv2/opencv.hpp> 2 #include <opencv2/legacy/compat.hpp> 3 using namespace std; 4 #pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"") 5 void FillWhite(IplImage *pImage) 6 { 7 cvRectangle(pImage, cvPoint(0, 0), cvPoint(pImage->width, pImage->height), CV_RGB(255, 255, 255), CV_FILLED); 8 } 9 // 建立灰度圖像的直方圖 10 CvHistogram* CreateGrayImageHist(IplImage **ppImage) 11 { 12 int nHistSize = 256; 13 float fRange[] = { 0, 255 }; //灰度級的範圍 14 float *pfRanges[] = { fRange }; 15 CvHistogram *pcvHistogram = cvCreateHist(1, &nHistSize, CV_HIST_ARRAY, pfRanges); 16 cvCalcHist(ppImage, pcvHistogram); 17 return pcvHistogram; 18 } 19 // 根據直方圖建立直方圖圖像 20 IplImage* CreateHisogramImage(int nImageWidth, int nScale, int nImageHeight, CvHistogram *pcvHistogram) 21 { 22 IplImage *pHistImage = cvCreateImage(cvSize(nImageWidth * nScale, nImageHeight), IPL_DEPTH_8U, 1); 23 FillWhite(pHistImage); 24 25 //統計直方圖中的最大直方塊 26 float fMaxHistValue = 0; 27 cvGetMinMaxHistValue(pcvHistogram, NULL, &fMaxHistValue, NULL, NULL); 28 29 //分別將每一個直方塊的值繪製到圖中 30 int i; 31 for (i = 0; i < nImageWidth; i++) 32 { 33 float fHistValue = cvQueryHistValue_1D(pcvHistogram, i); //像素爲i的直方塊大小 34 int nRealHeight = cvRound((fHistValue / fMaxHistValue) * nImageHeight); //要繪製的高度 35 cvRectangle(pHistImage, 36 cvPoint(i * nScale, nImageHeight - 1), 37 cvPoint((i + 1) * nScale - 1, nImageHeight - nRealHeight), 38 cvScalar(i, 0, 0, 0), 39 CV_FILLED 40 ); 41 } 42 return pHistImage; 43 } 44 int main(int argc, char** argv) 45 { 46 const char *pstrWindowsSrcTitle = "原圖"; 47 const char *pstrWindowsGrayTitle = "灰度圖"; 48 const char *pstrWindowsHistTitle = "直方圖"; 49 const char *pstrWindowsGrayEqualizeTitle = "灰度圖-均衡化後"; 50 const char *pstrWindowsHistEqualizeTitle = "直方圖-均衡化後"; 51 52 // 從文件中加載原圖 53 IplImage *pSrcImage = cvLoadImage("xh.jpg", CV_LOAD_IMAGE_UNCHANGED); 54 IplImage *pGrayImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 1); 55 IplImage *pGrayEqualizeImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 1); 56 57 // 灰度圖 58 cvCvtColor(pSrcImage, pGrayImage, CV_BGR2GRAY); 59 // 直方圖圖像數據 60 int nHistImageWidth = 255; 61 int nHistImageHeight = 150; 62 int nScale = 2; 63 64 // 灰度直方圖及直方圖圖像 65 CvHistogram *pcvHistogram = CreateGrayImageHist(&pGrayImage); 66 IplImage *pHistImage = CreateHisogramImage(nHistImageWidth, nScale, nHistImageHeight, pcvHistogram); 67 68 // 均衡化 69 cvEqualizeHist(pGrayImage, pGrayEqualizeImage); 70 71 // 均衡化後的灰度直方圖及直方圖圖像 72 CvHistogram *pcvHistogramEqualize = CreateGrayImageHist(&pGrayEqualizeImage); 73 IplImage *pHistEqualizeImage = CreateHisogramImage(nHistImageWidth, nScale, nHistImageHeight, pcvHistogramEqualize); 74 75 76 // 顯示 77 cvNamedWindow(pstrWindowsGrayTitle, CV_WINDOW_AUTOSIZE); 78 cvNamedWindow(pstrWindowsHistTitle, CV_WINDOW_AUTOSIZE); 79 cvNamedWindow(pstrWindowsGrayEqualizeTitle, CV_WINDOW_AUTOSIZE); 80 cvNamedWindow(pstrWindowsHistEqualizeTitle, CV_WINDOW_AUTOSIZE); 81 //顯示代碼…. 82 cvShowImage(pstrWindowsGrayTitle, pGrayImage);//顯示灰度圖 83 cvShowImage(pstrWindowsHistTitle, pHistImage);//顯示灰度直方圖 84 cvShowImage(pstrWindowsGrayEqualizeTitle, pGrayEqualizeImage);//顯示均衡化後的灰度圖 85 cvShowImage(pstrWindowsHistEqualizeTitle, pHistEqualizeImage);//顯示均衡化後的灰度直方圖 86 87 //顯示代碼…. 88 cvWaitKey(0); 89 90 //回收資源代碼… 91 cvDestroyWindow(pstrWindowsGrayTitle); 92 cvDestroyWindow(pstrWindowsHistTitle); 93 cvDestroyWindow(pstrWindowsGrayEqualizeTitle); 94 cvDestroyWindow(pstrWindowsHistEqualizeTitle); 95 96 cvReleaseImage(&pSrcImage); 97 cvReleaseImage(&pHistImage); 98 cvReleaseImage(&pGrayEqualizeImage); 99 cvReleaseImage(&pHistEqualizeImage); 100 101 return 0;
輸出【均衡化後進行輪廓檢測效果會更佳】:
十、彩色直方圖均衡化
主要函數介紹:
1)cvSplit
函數功能:分割多通道數組成幾個單通道數組或者從數組中提取一個通道。
函數原型:
/* Splits a multi-channel array into the set of single-channel arrays or
extracts particular [color] plane */
CVAPI(void) cvSplit(
const CvArr* src,
CvArr* dst0,
CvArr* dst1,
CvArr* dst2,
CvArr* dst3
);
參數說明:
第一個參數表示輸入的多通道數組即輸入圖像。
第二,三,四,五個參數分別表示輸出的單通道數組。
2)cvMerge
函數功能:分割多通道數組成幾個單通道數組或者從數組中提取一個通道。
函數原型:
/* Merges a set of single-channel arrays into the single multi-channel array
or inserts one particular [color] plane to the array */
CVAPI(void) cvMerge(
const CvArr* src0,
const CvArr* src1,
const CvArr* src2,
const CvArr* src3,
CvArr* dst
);
參數說明:
第一,二,三,四個參數表示輸入的單通道數組。
第五個參數分別表示合併後的多通道數組即輸出圖像。
1 #include <opencv2/opencv.hpp> 2 using namespace std; 3 #pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"") 4 //彩色圖像的直方圖均衡化 5 IplImage* EqualizeHistColorImage(IplImage *pImage) 6 { 7 IplImage *pEquaImage = cvCreateImage(cvGetSize(pImage), pImage->depth, 3); 8 9 // 原圖像分紅各通道後再均衡化,最後合併即彩色圖像的直方圖均衡化 10 const int MAX_CHANNEL = 4; 11 IplImage *pImageChannel[MAX_CHANNEL] = { NULL }; 12 13 int i; 14 for (i = 0; i < pImage->nChannels; i++) 15 pImageChannel[i] = cvCreateImage(cvGetSize(pImage), pImage->depth, 1); 16 17 cvSplit(pImage, pImageChannel[0], pImageChannel[1], pImageChannel[2], pImageChannel[3]); 18 19 for (i = 0; i < pImage->nChannels; i++) 20 cvEqualizeHist(pImageChannel[i], pImageChannel[i]); 21 22 cvMerge(pImageChannel[0], pImageChannel[1], pImageChannel[2], pImageChannel[3], pEquaImage); 23 24 for (i = 0; i < pImage->nChannels; i++) 25 cvReleaseImage(&pImageChannel[i]); 26 27 return pEquaImage; 28 } 29 int main(int argc, char** argv) 30 { 31 const char *pstrWindowsSrcTitle = "原圖"; 32 const char *pstrWindowsHisEquaTitle = "直方圖均衡化後"; 33 34 // 從文件中加載原圖 35 IplImage *pSrcImage = cvLoadImage("01.jpg", CV_LOAD_IMAGE_UNCHANGED); 36 IplImage *pHisEquaImage = EqualizeHistColorImage(pSrcImage); 37 38 cvNamedWindow(pstrWindowsSrcTitle, CV_WINDOW_AUTOSIZE); 39 cvNamedWindow(pstrWindowsHisEquaTitle, CV_WINDOW_AUTOSIZE); 40 cvShowImage(pstrWindowsSrcTitle, pSrcImage); 41 cvShowImage(pstrWindowsHisEquaTitle, pHisEquaImage); 42 43 44 cvWaitKey(0); 45 46 cvDestroyWindow(pstrWindowsSrcTitle); 47 cvDestroyWindow(pstrWindowsHisEquaTitle); 48 cvReleaseImage(&pSrcImage); 49 cvReleaseImage(&pHisEquaImage); 50 return 0; 51 }
輸出:
結語:【opencv入門篇】到此完結,但學習永遠不會中止。網絡最大的好處就是你幾乎能夠找到你想要的任何答案,只要你想去學。站在大牛的肩上,但願咱們能看得更遠!
新手上路,但願老司機能多多指教:)
主要參考: