圖像對比度增強的方法可以分成兩類:一類是直接對比度增強方法;另一類是間接對比度增強方法。
直方圖拉伸和直方圖均衡化是兩種最常見的間接對比度增強方法。
直方圖拉伸是通過對比度拉伸對直方圖進行調整,從而“擴大”前景和背景灰度的差別,以達到增強對比度的目的,這種方法可以利用線性或非線性的方法來實現;
直方圖均衡化則通過使用累積函數對灰度值進行“調整”以實現對比度的增強。
1.直方圖拉伸
就是擴大將圖像灰度的域值的一個過程,但是經常是基於灰度圖像進行處理,以前在MATlab上對比度增強調用直方圖函數就幾行代碼,但都是灰度圖像上處理,需要在彩色圖像進行處理,看別人的思想是從RGB-YUV-RGB的過程,在YUV空間增強再轉回來,我跟着原理寫代碼,出了很多問題。詳見http://blog.csdn.net/abcjennifer/article/details/7428737
/* *@Function: Color image contrast enhancement *@Date: 2012-4-5 *@Author: 張睿卿 */ int ImageStretchByHistogram(IplImage *src1,IplImage *dst1) /************************************************* Function: 通過直方圖變換進行圖像增強,將圖像灰度的域值拉伸到0-255 src1: 單通道灰度圖像 dst1: 同樣大小的單通道灰度圖像 *************************************************/ { assert(src1->width==dst1->width); double p[256],p1[256],num[256]; memset(p,0,sizeof(p)); memset(p1,0,sizeof(p1)); memset(num,0,sizeof(num)); int height=src1->height; int width=src1->width; long wMulh = height * width; //statistics for(int x=0;x<src1->width;x++) { for(int y=0;y<src1-> height;y++){ uchar v=((uchar*)(src1->imageData + src1->widthStep*y))[x]; num[v]++; } } //calculate probability for(int i=0;i<256;i++) { p[i]=num[i]/wMulh; } //p1[i]=sum(p[j]); j<=i; for(int i=0;i<256;i++) { for(int k=0;k<=i;k++) p1[i]+=p[k]; } // histogram transformation for(int x=0;x<src1->width;x++) { for(int y=0;y<src1-> height;y++){ uchar v=((uchar*)(src1->imageData + src1->widthStep*y))[x]; ((uchar*)(dst1->imageData + dst1->widthStep*y))[x]= p1[v]*255+0.5; } } return 0; } void CCVMFCView::OnYcbcrY() { IplImage* Y = cvCreateImage(cvGetSize(workImg),IPL_DEPTH_8U,1); IplImage* Cb= cvCreateImage(cvGetSize(workImg),IPL_DEPTH_8U,1); IplImage* Cr = cvCreateImage(cvGetSize(workImg),IPL_DEPTH_8U,1); IplImage* Compile_YCbCr= cvCreateImage(cvGetSize(workImg),IPL_DEPTH_8U,3); IplImage* dst1=cvCreateImage(cvGetSize(workImg),IPL_DEPTH_8U,3); int i; cvCvtColor(workImg,dst1,CV_BGR2YCrCb); cvSplit(dst1,Y,Cb,Cr,0); ImageStretchByHistogram(Y,dst1); for(int x=0;x<workImg->height;x++) { for(int y=0;y<workImg->width;y++) { CvMat* cur=cvCreateMat(3,1,CV_32F); cvmSet(cur,0,0,((uchar*)(dst1->imageData+x*dst1->widthStep))[y]); cvmSet(cur,1,0,((uchar*)(Cb->imageData+x*Cb->widthStep))[y]); cvmSet(cur,2,0,((uchar*)(Cr->imageData+x*Cr->widthStep))[y]); for(i=0;i<3;i++) { double xx=cvmGet(cur,i,0); ((uchar*)Compile_YCbCr->imageData+x*Compile_YCbCr->widthStep)[y*3+i]=xx; } } } cvCvtColor(Compile_YCbCr,workImg,CV_YCrCb2BGR); m_ImageType=3; Invalidate(); }
其中int ImageStretchByHistogram(IplImage *src1,IplImage *dst1) 是可以運行的,實現了灰度圖像增強;
void CCVMFCView::OnYcbcrY() 我處理不好,只好呼喚睿卿 本人了。附上一個基於opencv已經實現灰度圖像增強的代碼.http://blog.csdn.net/zhaiwenjuan/article/details/6596011
#include "stdafx.h" #include "cv.h" #include "highgui.h" #include #include int ImageStretchByHistogram(IplImage *src,IplImage *dst); int _tmain(int argc, _TCHAR* argv[]) { IplImage * pImg; pImg=cvLoadImage("c:/lena.jpg",-1); //創建一個灰度圖像 IplImage* GrayImage = cvCreateImage(cvGetSize(pImg), IPL_DEPTH_8U, 1); IplImage* dstGrayImage = cvCreateImage(cvGetSize(pImg), IPL_DEPTH_8U, 1); cvCvtColor(pImg, GrayImage, CV_BGR2GRAY); ImageStretchByHistogram(GrayImage,dstGrayImage); cvNamedWindow( "dstGrayImage", 1 ); //創建窗口 cvNamedWindow( "GrayImage", 1 ); //創建窗口 cvShowImage( "dstGrayImage", dstGrayImage ); //顯示圖像 cvShowImage( "GrayImage", GrayImage ); //顯示圖像 cvWaitKey(0); //等待按鍵 cvDestroyWindow( "dstGrayImage" );//銷毀窗口 cvDestroyWindow( "GrayImage" );//銷毀窗口 cvReleaseImage( &pImg ); //釋放圖像 cvReleaseImage( &GrayImage ); //釋放圖像 cvReleaseImage( &dstGrayImage ); //釋放圖像 return 0; } int ImageStretchByHistogram(IplImage *src,IplImage *dst) /************************************************* Function: Description: 因為攝像頭圖像質量差,需要根據直方圖進行圖像增強, 將圖像灰度的域值拉伸到0-255 Calls: Called By: Input: 單通道灰度圖像 Output: 同樣大小的單通道灰度圖像 Return: Others: http://www.xiaozhou.net/ReadNews.asp?NewsID=771 DATE: 2007-1-5 *************************************************/ { //p[]存放圖像各個灰度級的出現概率; //p1[]存放各個灰度級之前的概率和,用於直方圖變換; //num[]存放圖象各個灰度級出現的次數; assert(src->width==dst->width); float p[256],p1[256],num[256]; //清空三個數組 memset(p,0,sizeof(p)); memset(p1,0,sizeof(p1)); memset(num,0,sizeof(num)); int height=src->height; int width=src->width; long wMulh = height * width; //求存放圖象各個灰度級出現的次數 // to do use openmp for(int x=0;x { for(int y=0;y { uchar v=((uchar*)(src->imageData + src->widthStep*y))[x]; num[v]++; } } //求存放圖像各個灰度級的出現概率 for(int i=0;i<256;i++) { p[i]=num[i]/wMulh; } //求存放各個灰度級之前的概率和 for(int i=0;i<256;i++) { for(int k=0;k<=i;k++) p1[i]+=p[k]; } //直方圖變換 // to do use openmp for(int x=0;x { for(int y=0;y { uchar v=((uchar*)(src->imageData + src->widthStep*y))[x]; ((uchar*)(dst->imageData + dst->widthStep*y))[x]= p1[v]*255+0.5; } } return 0; }
2.既然直方圖拉伸這條路走不通,只好試試,另一條,直方圖均衡化了,還好我比較熟。
//圖像增強- 彩色直方圖均衡化 #include <cv.h> #include <cxcore.h> #include <highgui.h> #include"opencv2/imgproc/imgproc.hpp" using namespace std; //彩色圖像的直方圖均衡化 IplImage* EqualizeHistColorImage(IplImage *pImage) { IplImage *pEquaImage = cvCreateImage(cvGetSize(pImage), pImage->depth, 3); // 原圖像分成各通道后再均衡化,最后合並即彩色圖像的直方圖均衡化 const int MAX_CHANNEL = 4; IplImage *pImageChannel[MAX_CHANNEL] = {NULL}; int i; for (i = 0; i < pImage->nChannels; i++) pImageChannel[i] = cvCreateImage(cvGetSize(pImage), pImage->depth, 1); cvSplit(pImage, pImageChannel[0], pImageChannel[1], pImageChannel[2], pImageChannel[3]); for (i = 0; i < pImage->nChannels; i++) cvEqualizeHist(pImageChannel[i], pImageChannel[i]); cvMerge(pImageChannel[0], pImageChannel[1], pImageChannel[2], pImageChannel[3], pEquaImage); for (i = 0; i < pImage->nChannels; i++) cvReleaseImage(&pImageChannel[i]); return pEquaImage; } int main( int argc, char** argv ) { const char *pstrWindowsSrcTitle = "原圖"; const char *pstrWindowsHisEquaTitle = "直方圖均衡化后"; // 從文件中加載原圖 IplImage *pSrcImage = cvLoadImage("lena.jpg", CV_LOAD_IMAGE_UNCHANGED); IplImage *pHisEquaImage = EqualizeHistColorImage(pSrcImage); cvNamedWindow(pstrWindowsSrcTitle, CV_WINDOW_AUTOSIZE); cvNamedWindow(pstrWindowsHisEquaTitle, CV_WINDOW_AUTOSIZE); cvShowImage(pstrWindowsSrcTitle, pSrcImage); cvShowImage(pstrWindowsHisEquaTitle, pHisEquaImage); cvWaitKey(0); cvDestroyWindow(pstrWindowsSrcTitle); cvDestroyWindow(pstrWindowsHisEquaTitle); cvReleaseImage(&pSrcImage); cvReleaseImage(&pHisEquaImage); return 0; }