彩色的图像其实是用一个多通道数组来存储的,每个单通道数组中的元素的取值范围都是0到255。
直方图均衡化可增强图像效果,增加对比度,睫毛头发德国细小物体都要清晰很多。
直方图的反向投影算法。通过鼠标的操作进行截屏,也就是设置兴趣区,用键盘控制兴趣区的平移、放大及缩小,同时将截屏保存下来。
一、灰度直方图均衡:
#include "stdafx.h"
#include"highgui.h"
#include"opencv2/opencv.hpp"
#include"cxcore.h"
#define cvQueryHistValue_1D(hist, idx0) \
((float)cvGetReal1D((hist)->bins, (idx0)))
using namespace std;
#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
void FillWhite(IplImage*pImage)
{
cvRectangle(pImage,cvPoint(0,0),cvPoint(pImage->width,pImage->height),CV_RGB(255,255,255),CV_FILLED);
}
//grayscale histogram
CvHistogram* CreateGrayImageHist(IplImage** ppImage)
{
int nHistSize = 256;
float fRanges[] = { 0, 255 };//range of gray level
float*pfRanges[] = {fRanges};
CvHistogram* pcvHistogram = cvCreateHist(1, &nHistSize, CV_HIST_ARRAY, pfRanges);
cvCalcHist(ppImage,pcvHistogram);
return pcvHistogram;
}
//create histogram image according to histogram
IplImage* CreateHistogram(int nImageWidth,int nScale, int nImageHeight, CvHistogram* pcvHistogram)
{
IplImage*pHistImage = cvCreateImage(cvSize(nImageWidth, nImageHeight), IPL_DEPTH_8U,1);
FillWhite(pHistImage);
//caculate the max straight square
float fMaxHistogram = 0;
cvGetMinMaxHistValue(pcvHistogram,NULL,&fMaxHistogram,NULL,NULL);
//draw each square value to the map
int i;
for ( i = 0; i <nImageWidth; i++)
{
float fHistValue = cvQueryHistValue_1D(pcvHistogram,i);//size of the ith pixel
int nRealHeight = cvRound((fHistValue / fMaxHistogram)*nImageHeight);//the height needed draw
cvRectangle(pHistImage,cvPoint(i*nScale,nImageHeight-1),cvPoint((i+1)*nScale-1,nImageHeight-nRealHeight),cvScalar(i,0,0,0),CV_FILLED);
}
return pHistImage;
}
int main(int argc, char ** argv)
{
const char * pstrWindowsSrcTitle = "The original Image";
const char * pstrWindowsGrayTitle = "Gray";
const char * pstrWindowsHistTitle = "Histogram";
const char * pstrWindowsGrayEqualizeTitle = "Gray-Equalization";
const char * pstrWindowsHistEqualizeTitle = "Historag-Equalization";
IplImage* pSrcImage = cvLoadImage("E:\\图片\\11.JPG");
IplImage* pGrayImage = cvCreateImage(cvGetSize(pSrcImage),IPL_DEPTH_8U,1);
IplImage* pGrayEqualizeImage = cvCreateImage(cvGetSize(pSrcImage),IPL_DEPTH_8U,1);
cvCvtColor(pSrcImage,pGrayImage,CV_BGR2GRAY);
int nHistImageWidth = 255;
int nHistImageHeight = 150;
int nScale = 2;
//gray histogram and histogram image
CvHistogram* pcvHistogram = CreateGrayImageHist(&pGrayEqualizeImage);
IplImage* pHistImage = CreateHistogram(nHistImageWidth, nScale, nHistImageHeight, pcvHistogram);
//Equalization
cvEqualizeHist(pGrayImage,pGrayEqualizeImage);
//gray histogram and histogram image after equalization
CvHistogram* pcvHistogramEqualize = CreateGrayImageHist(&pGrayEqualizeImage);
IplImage* pHistEqualizeImage = CreateHistogram(nHistImageWidth, nScale, nHistImageHeight, pcvHistogramEqualize);
cvShowImage(pstrWindowsSrcTitle, pSrcImage);
cvShowImage(pstrWindowsGrayTitle, pGrayImage);
cvShowImage(pstrWindowsHistTitle, pHistImage);
cvShowImage(pstrWindowsGrayEqualizeTitle, pGrayEqualizeImage);
cvShowImage(pstrWindowsHistEqualizeTitle, pHistEqualizeImage);
cvWaitKey();
}
二、彩色直方图均衡
#include "stdafx.h"
#include"highgui.h"
#include"opencv2/opencv.hpp"
#include"cxcore.h"
#define cvQueryHistValue_1D(hist, idx0) \
((float)cvGetReal1D((hist)->bins, (idx0)))
using namespace std;
#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
IplImage* EqualizwHistColorImage(IplImage* pImage)
{
IplImage* pEquaImage = cvCreateImage(cvGetSize(pImage),pImage->depth,3);
//equalize the original image after divided into 3 channels , then merge them
const int MAX_CHANNNEL = 4;
IplImage* pImageChannel[MAX_CHANNNEL] = {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 = "The original Image";
const char * pstrWindowsHistEqualizeTitle = "Historag-Equalization";
IplImage* pSrcImage = cvLoadImage("E:\\图片\\11.JPG");
//Equalization
IplImage* pImageHistogram = NULL;
pImageHistogram = EqualizwHistColorImage(pSrcImage);
cvShowImage(pstrWindowsSrcTitle, pSrcImage);
cvShowImage(pstrWindowsHistEqualizeTitle, pImageHistogram);
cvWaitKey();
}
直方图的反向投影算法:原理
两张灰度图,其中一张图像尺寸大于等于另一张,其中尺寸较大的图像作为查询图像,另一张为模板图像,直方图反向投影变换的基本原理是:
(1)从尺寸较大的图像的左上角(0,0)开始,切割一块与较小图像尺寸一致的临时图像;
(2)计算临时图像的直方图;
(3)用临时图像的直方图和尺寸较小的图像的直方图对比,对比结果记为c;
(4)直方图对比结果c,就是结果图像(0,0)处的像素值;
(5)逐个像素移动进行图像切割,对比直方图,并记录直方图对比结果;
(6)重复(1)~(5)步直到输入图像的右下角。
需要注意的地方:
(1) 需要在代码实现中加入对图像尺寸大小的判断,如果模版图像尺寸小于查找图像,则程序正常执行,如果等于,这相当于进行直方图比较,如果大于,则应该提示程序无法正常执行
(2)此算法执行效率较低,在使用之前尤其需要注意图像的大小,直方图的维数,对比方式,在计算之前可以考虑对图像进行ColorReduce。
一、灰度直方图反向投影程序
#include "stdafx.h"
#include "opencv2/opencv.hpp"
#include "highgui.h"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
IplImage* src = cvLoadImage("E:\\图片\\1.bmp");
IplImage* src1 = cvLoadImage("E:\\图片\\2.bmp");
int hist_size = 256;
float range[] = {0,255};
float *ranges[] = {range};
IplImage* gray_plan = cvCreateImage(cvGetSize(src),8,1);
cvCvtColor(src,gray_plan,CV_BGR2GRAY);
CvHistogram* Gray_hist = cvCreateHist(1,&hist_size,CV_HIST_ARRAY,ranges,1);
cvCalcHist(&gray_plan,Gray_hist,0,0);//calculate histogram automatically
//cvNormalizeHist(Gray_hist,1.0);
IplImage* gray_plan1 = cvCreateImage(cvGetSize(src1), 8, 1);
cvCvtColor(src1, gray_plan1, CV_BGR2GRAY);
IplImage* dst = cvCreateImage(cvGetSize(gray_plan1),IPL_DEPTH_8U,1);
cvCalcBackProject(&gray_plan1,dst,Gray_hist);//reversw projection
cvEqualizeHist(dst,dst);
cvShowImage("first image",src);
cvShowImage("revers image", dst);
cvWaitKey();
return 0;
}
二、彩色直方图反向投影程序
#include "stdafx.h"
#include "opencv2/opencv.hpp"
#include "highgui.h"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
IplImage* src = cvLoadImage("E:\\图片\\11.jpg");
IplImage* src1 = cvLoadImage("E:\\图片\\11.jpg");
printf("%f\n", src->origin); //src->origin=0 left-top
/*cvShowImage("first image", src);*/
//cvShowImage("second image", src1);
CvRect roi_rect_dst;
roi_rect_dst.x = 100; roi_rect_dst.y = 100;
roi_rect_dst.width = 300; roi_rect_dst.height = 300;
int c = 30, d = 30;
cvSetImageROI(src1, roi_rect_dst);
cvShowImage("second image1", src1);
IplImage* gray_plan = cvCreateImage(cvGetSize(src),8,1);
IplImage* h_plan = cvCreateImage(cvGetSize(src), 8, 1);
IplImage* s_plan = cvCreateImage(cvGetSize(src), 8, 1);
IplImage* v_plan = cvCreateImage(cvGetSize(src), 8, 1);
IplImage* plans[] = { h_plan, s_plan, v_plan };
IplImage* hsv = cvCreateImage(cvGetSize(src), 8, 3);
cvCvtColor(src, hsv, CV_BGR2HSV);
cvSplit(hsv,h_plan,s_plan,v_plan,0);
printf("h%d\n", h_plan->widthStep);
printf("s%d\n", s_plan->widthStep);
printf("v%d\n", v_plan->widthStep);
IplImage* gray_plan1 = cvCreateImage(cvGetSize(src1), 8, 1);
IplImage* h_plan1 = cvCreateImage(cvGetSize(src1), 8, 1);
IplImage* s_plan1 = cvCreateImage(cvGetSize(src1), 8, 1);
IplImage* v_plan1 = cvCreateImage(cvGetSize(src1), 8, 1);
IplImage* plans1[] = { h_plan1, s_plan1, v_plan1};
IplImage* hsv1 = cvCreateImage(cvGetSize(src1), 8, 3);
cvCvtColor(src1, hsv1, CV_BGR2HSV);
cvSplit(hsv1, h_plan1, s_plan1, v_plan1, 0);
printf("h%d\n", h_plan1->widthStep);
printf("s%d\n", s_plan1->widthStep);
printf("v%d\n", v_plan1->widthStep);
int h_bins = 20, s_bins = 20, v_bins = 20;
int hist_size[] = {h_bins,s_bins,v_bins};
float h_ranges[] = {0,255};
float s_ranges[] = { 0, 255 };
float v_ranges[] = { 0, 255 };
float*ranges[] = {h_ranges,s_ranges,v_ranges};
CvHistogram* hist;
hist = cvCreateHist(3,hist_size,CV_HIST_ARRAY,ranges,1);
cvCalcHist(plans1,hist,0,0);
IplImage* back_project = cvCreateImage(cvGetSize(src),8,1);
cvZero(back_project);
//cvNormalizeHist(Gray_hist,1.0);
cvCalcBackProject(plans,back_project,hist);//reversw projection
cvShowImage("first image",src);
cvShowImage("revers image", back_project);
cvWaitKey();
return 0;
}
三、鼠标点击事件
#include "stdafx.h"
#include"highgui.h"
#include"opencv2/opencv.hpp"
#include"cxcore.h"
using namespace std;
void my_mouse_callback(
int Event, int x, int y, int flags, void *param
);
CvRect box;
bool drawing_box = false;
void draw_box(IplImage *img, CvRect rect){
// cvRectangle 会修改img的数据
cvRectangle(
img,
cvPoint(box.x, box.y),
cvPoint(box.x + box.width, box.y + box.height),
cvScalar(0xff, 0xff, 0x00)
);
}
int main(int argc, char ** argv)
{
box = cvRect(-1, -1, 0, 0);
IplImage* img = cvCreateImage(
cvSize(200, 200),
IPL_DEPTH_8U,
3
);
cvZero(img);
// 函数 cvCloneImage 制作图像的完整拷贝包括头、ROI和数据
IplImage * temp = cvCloneImage(img);
cvNamedWindow("Box Example");
cvSetMouseCallback(
"Box Example",
my_mouse_callback,
(void *)img
);
while (1){
// 把 img的所有 复制给 temp, temp 是img 此时的一个副本
// draw_box(temp, box), 由于此时是鼠标移动的时候,所以最终的rect还
// 没有确定,说以不能把temp 该成img, 如果改成img, 那么每隔15ms
// img的数据就会跟新一次,同样,cvshowimage中的一定要为现在的temp
temp=cvCloneImage(img);// img -> temp
// 回调函数修改的是img
if (drawing_box)
draw_box(temp, box);
cvShowImage("Box Example", temp);
if (cvWaitKey(15) == 27) break;
}
cvReleaseImage(&img);
cvReleaseImage(&temp);
cvDestroyWindow("Box Example");
}
void my_mouse_callback(int Event, int x, int y, int flags, void *param){
IplImage* curImg = (IplImage *)param;
switch (Event){
case CV_EVENT_MOUSEMOVE:{
if (drawing_box){
box.width = x - box.x;
box.height = y - box.y;
}
}
break;
case CV_EVENT_LBUTTONDOWN:{
drawing_box = true;
box = cvRect(x, y, 0, 0);
}
break;
case CV_EVENT_LBUTTONUP:{
drawing_box = false;
draw_box(curImg, box);
}
break;
}
}
四、鼠标和键盘处理事件
#include "stdafx.h"
#include"highgui.h"
#include"opencv2/opencv.hpp"
#include"cxcore.h"
using namespace std;
using namespace cv;
#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
CvPoint pt1 = Point(0, 0);
CvPoint pt2 = Point(0, 0);
bool is_selecting = false;
void cvMouseCallback(int mouseEvent, int x, int y, int flags, void* param)
{
switch(mouseEvent)
{
case CV_EVENT_LBUTTONDOWN:
pt1 = Point(x, y);
pt2 = Point(x, y);
is_selecting = true;
break;
case CV_EVENT_MOUSEMOVE:
if (is_selecting)
pt2 = Point(x,y);
break;
case CV_EVENT_LBUTTONUP:
pt2 = Point(x,y);
is_selecting = false;
break;
}
return;
}
int main(int argc, char ** argv)
{
CvRect rect = cvRect(pt1.x, pt1.y, abs(pt2.x - pt1.x), abs(pt2.y - pt1.y));
IplImage* pSrcImage = cvLoadImage("E:\\图片\\11.JPG");
IplImage* Img1;
cvNamedWindow("IMG",0);
cvSetMouseCallback("IMG",cvMouseCallback);
//Equalization
bool SHIFTER_ON = false;
while (true)
{
Img1 = cvCloneImage(pSrcImage);
cvRectangle(Img1, pt1, pt2, cvScalar(255, 255, 255));
cvShowImage("IMG", pSrcImage);
cvShowImage("IM1G", Img1);
char key = cvWaitKey(10);
switch (key)
{
case'\t':
SHIFTER_ON = !SHIFTER_ON; break;
case 'a':
pt1.x--; pt2.x--; break;
case 's':
pt1.y++; pt2.y++; break;
case 'd':
pt1.x++; pt2.x++; break;
case 'w':
pt1.y--; pt2.y--; break;
//AMPLIFICATION AND narrow ROI,the mainly operation is shifteration for ege of initial ROI
case '1':
if (SHIFTER_ON) pt1.x--;
else pt2.x--;
break;
case '2':
if (SHIFTER_ON) pt2.y++;
else pt1.y++;
break;
case '3':
if (SHIFTER_ON) pt2.x++;
else pt1.x++;
break;
case '4':
if (SHIFTER_ON) pt1.y--;
else pt2.y--;
break;
case '\r':
cvSetImageROI(Img1, rect);
break;
cvSaveImage("e:\\879,jpg", Img1);
}
if (key == 27) break;
}
cvReleaseImage(&pSrcImage);
cvReleaseImage(&Img1);
return 0;
}