很久之前看过一篇关于色彩平衡文章,在该文章中介绍了一种非常简单高效的
色彩平衡算法。下图是算法的演示效果(左边为处理后的图像,右边为处理前的图像)。
从图中可以看出算法有效的改善的图像的色彩,使得色彩更加的真实。
下面是实现代码
#include "stdafx.h"
#include "cv.h"
#include "cxcore.h"
#include "highgui.h"
#pragma comment(lib, "cv.lib")
#pragma comment(lib, "cxcore.lib")
#pragma comment(lib, "highgui.lib")
void color_balance(IplImage *img)
{
int histo[256] = {0};
int num_of_pixels = img->width*img->height;
for(int y = 0; y < img->height; ++y)
{
uchar *data = (uchar*)(img->imageData + y*img->widthStep);
for(int x = 0; x < img->width; ++x)
{
histo[data[x]] += 1;
}
}
for(int i = 1; i < 256; ++i)
histo[i] = histo[i] + histo[i-1];
double s = 0.1;
int vmin = 0;
while (histo[vmin + 1] <= cvRound(num_of_pixels*s/2))
vmin = vmin + 1;
int vmax = 255 - 1;
while( histo[vmax - 1] > cvRound(num_of_pixels*(1 - s/2)))
{
vmax = vmax - 1;
}
if (vmax < 255 - 1)
vmax = vmax + 1;
for(int y = 0; y < img->height; ++y)
{
uchar *data = (uchar*)(img->imageData + y*img->widthStep);
for(int x = 0; x < img->width; ++x)
{
if(data[x] < vmin)
data[x] = vmin;
if(data[x] > vmax)
data[x] = vmax;
}
}
for(int y = 0; y < img->height; ++y)
{
uchar *data = (uchar*)(img->imageData + y*img->widthStep);
for(int x = 0; x < img->width; ++x)
{
data[x] = cvRound((data[x] - vmin)*255.0/(vmax - vmin));
}
}
}
int _tmain(int argc, _TCHAR* argv[])
{
IplImage *srcImg = cvLoadImage("D:\\colorbalance.jpg");
IplImage *dstImg = cvCreateImage(cvGetSize(srcImg), 8, 3);
IplImage *redCh = cvCreateImage(cvGetSize(srcImg), 8, 1);
IplImage *greenCh = cvCreateImage(cvGetSize(srcImg), 8, 1);
IplImage *blueCh = cvCreateImage(cvGetSize(srcImg), 8, 1);
cvSplit(srcImg, blueCh, greenCh, redCh, NULL);
color_balance(redCh);
color_balance(greenCh);
color_balance(blueCh);
cvMerge(blueCh, greenCh, redCh, NULL, dstImg);
cvNamedWindow("src", CV_WINDOW_AUTOSIZE);
cvShowImage("src", srcImg);
cvNamedWindow("dst", CV_WINDOW_AUTOSIZE);
cvShowImage("dst", dstImg);
cvWaitKey(0);
return 0;
}
2
3 #include " cv.h "
4 #include " cxcore.h "
5 #include " highgui.h "
6
7 #pragma comment(lib, "cv.lib")
8 #pragma comment(lib, "cxcore.lib")
9 #pragma comment(lib, "highgui.lib")
10
11 void color_balance(IplImage * img)
12 {
13 int histo[ 256 ] = { 0 };
14 int num_of_pixels = img -> width * img -> height;
15 for ( int y = 0 ; y < img -> height; ++ y)
16 {
17 uchar * data = (uchar * )(img -> imageData + y * img -> widthStep);
18 for ( int x = 0 ; x < img -> width; ++ x)
19 {
20 histo[data[x]] += 1 ;
21 }
22 }
23
24 for ( int i = 1 ; i < 256 ; ++ i)
25 histo[i] = histo[i] + histo[i - 1 ];
26
27 double s = 0.1 ;
28 int vmin = 0 ;
29 while (histo[vmin + 1 ] <= cvRound(num_of_pixels * s / 2 ))
30 vmin = vmin + 1 ;
31 int vmax = 255 - 1 ;
32 while ( histo[vmax - 1 ] > cvRound(num_of_pixels * ( 1 - s / 2 )))
33 {
34 vmax = vmax - 1 ;
35 }
36 if (vmax < 255 - 1 )
37 vmax = vmax + 1 ;
38
39 for ( int y = 0 ; y < img -> height; ++ y)
40 {
41
42 uchar * data = (uchar * )(img -> imageData + y * img -> widthStep);
43 for ( int x = 0 ; x < img -> width; ++ x)
44 {
45 if (data[x] < vmin)
46 data[x] = vmin;
47 if (data[x] > vmax)
48 data[x] = vmax;
49 }
50 }
51
52 for ( int y = 0 ; y < img -> height; ++ y)
53 {
54
55 uchar * data = (uchar * )(img -> imageData + y * img -> widthStep);
56 for ( int x = 0 ; x < img -> width; ++ x)
57 {
58 data[x] = cvRound((data[x] - vmin) * 255.0 / (vmax - vmin));
59 }
60 }
61
62 }
63 int _tmain( int argc, _TCHAR * argv[])
64 {
65 IplImage * srcImg = cvLoadImage( " D:\\colorbalance.jpg " );
66 IplImage * dstImg = cvCreateImage(cvGetSize(srcImg), 8 , 3 );
67 IplImage * redCh = cvCreateImage(cvGetSize(srcImg), 8 , 1 );
68 IplImage * greenCh = cvCreateImage(cvGetSize(srcImg), 8 , 1 );
69 IplImage * blueCh = cvCreateImage(cvGetSize(srcImg), 8 , 1 );
70 cvSplit(srcImg, blueCh, greenCh, redCh, NULL);
71 color_balance(redCh);
72 color_balance(greenCh);
73 color_balance(blueCh);
74 cvMerge(blueCh, greenCh, redCh, NULL, dstImg);
75
76 cvNamedWindow( " src " , CV_WINDOW_AUTOSIZE);
77 cvShowImage( " src " , srcImg);
78
79 cvNamedWindow( " dst " , CV_WINDOW_AUTOSIZE);
80 cvShowImage( " dst " , dstImg);
81 cvWaitKey( 0 );
82
83 return 0 ;
84 }