今天加入了一些新功能:
1. YUV文件格式支持(yuv420p 420sp, yuv422, yuv444)
2. 亮度,色调,饱和度,对比度的调整。
3. 反色,灰度,阈值化操作。
4. 加入历史记录,以支持回退、前进等操作。
5. LOG模块和快捷键等等。
YUV文件格式支持
不了解YUV格式的同学可以先看看这个:
http://zh.wikipedia.org/wiki/YUV
Opencv提供了YUV的转换函数, 但是色彩会有些损失。所以根据公式自己写了一个。 我这个是最近邻插值算法,相对于双线性或者双三次插值比较简单。 感兴趣的读者也可以自己实现。
void _YUVtoBGR(Vec3b& rgb, const Vec3b& yuv) { int Y = yuv[0]; int U = yuv[1] - 128; int V = yuv[2] - 128; int R = (int)( Y + 1.403f * V); int G = (int)( Y - 0.344f * U - 0.714f * V); int B = (int)( Y + 1.770f * U); rgb[0]= saturate_cast<uchar>(B); rgb[1]= saturate_cast<uchar>(G); rgb[2]= saturate_cast<uchar>(R); } void _BGRtoYUV(const Vec3b& rgb, Vec3b& yuv) { int B = rgb[0]; int G = rgb[1]; int R = rgb[2]; int Y = (int)(0.299f * R + 0.587f * G + 0.114f * B); int U = (int)((B-Y) * 0.565f + 128); int V = (int)((R-Y) * 0.713f + 128); yuv[0]= saturate_cast<uchar>(Y); yuv[1]= saturate_cast<uchar>(U); yuv[2]= saturate_cast<uchar>(V); } void ImageYUV2BGR(Mat& img, PBYTE pYUV, int type) { CFunctionLog fl(__FUNCTION__); int w = img.cols; int h = img.rows; w = ALIGN_DOWN(w, 4); h = ALIGN_DOWN(h, 4); Vec3b yuv; switch(type) { case YUV_NV21: case YUV_NV12: { PBYTE pUV = pYUV+w*h; PBYTE pY = pYUV; int vidx = type == YUV_NV12 ? 1 : 2; int uidx = type == YUV_NV12 ? 2 : 1; for (int y = 0;y < h;y++) { for (int x = 0;x < w;x++) { yuv[0] = *pY++; yuv[uidx] = pUV[y/2*w+x/2*2]; yuv[vidx] = pUV[y/2*w+x/2*2+1]; _YUVtoBGR(img.at<Vec3b>(y, x), yuv); } } } break; case YUV_I420: case YUV_YV12: { PBYTE pY = pYUV; PBYTE pV = pYUV+w*h*5/4; PBYTE pU = pYUV+w*h; int uidx = type == YUV_I420 ? 1 : 2; int vidx = type == YUV_I420 ? 2 : 1; for (int y = 0;y < h;y++) { for (int x = 0;x < w;x++) { yuv[0] = *pY++; yuv[uidx] = pU[y/4*w+x/2+w*y/4%2]; yuv[vidx] = pV[y/4*w+x/2+w*y/4%2]; _YUVtoBGR(img.at<Vec3b>(y, x), yuv); } } } break; case YUV_YUYV: case YUV_UYVY: { int yidx = type == YUV_YUYV ? 0 : 1; int uidx = type == YUV_YUYV ? 1 : 0; int vidx = type == YUV_YUYV ? 3 : 2; PBYTE pY = pYUV + yidx; PBYTE pV = pYUV + vidx; PBYTE pU = pYUV + uidx; for (int y = 0;y < h;y++) { for (int x = 0;x < w;x++) { yuv[0] = *pY; pY+=2; if(x%2==0) { yuv[1] = *pU; yuv[2] = *pV; pU+=4; pV+=4; } _YUVtoBGR(img.at<Vec3b>(y, x), yuv); } } } break; case YUV_444: { PBYTE pY = pYUV; PBYTE pU = pYUV + w*h; PBYTE pV = pYUV + w*h*2; for (int y = 0;y < h;y++) { for (int x = 0;x < w;x++) { yuv[0] = *pY++; yuv[1] = *pU++; yuv[2] = *pV++; _YUVtoBGR(img.at<Vec3b>(y, x), yuv); } } } break; } } void ImageBGR2YUV(Mat& img, PBYTE pYUV, int type) { CFunctionLog fl(__FUNCTION__); int w = img.cols; int h = img.rows; w = ALIGN_DOWN(w, 4); h = ALIGN_DOWN(h, 4); Vec3b yuv; switch(type) { case YUV_NV21: case YUV_NV12: { PBYTE pUV = pYUV+w*h; PBYTE pY = pYUV; int vidx = type == YUV_NV12 ? 1 : 2; int uidx = type == YUV_NV12 ? 2 : 1; for (int y = 0;y < h;y++) { for (int x = 0;x < w;x++) { Vec3b c = img.at<Vec3b>(y, x); _BGRtoYUV(c, yuv); *pY++ = yuv[0]; if(y%2==0&&x%2==0) { pUV[y/2*w+x/2*2] = yuv[uidx]; pUV[y/2*w+x/2*2+1] = yuv[vidx]; } } } } break; case YUV_I420: case YUV_YV12: { PBYTE pY = pYUV; PBYTE pV = pYUV+w*h*5/4; PBYTE pU = pYUV+w*h; int uidx = type == YUV_I420 ? 1 : 2; int vidx = type == YUV_I420 ? 2 : 1; for (int y = 0;y < h;y++) { for (int x = 0;x < w;x++) { Vec3b c = img.at<Vec3b>(y, x); _BGRtoYUV(c, yuv); *pY++ = yuv[0]; if(y%2==0&&x%2==0) { *pU++ = yuv[uidx]; *pV++ = yuv[vidx]; } } } } break; case YUV_YUYV: case YUV_UYVY: { int yidx = type == YUV_YUYV ? 0 : 1; int uidx = type == YUV_YUYV ? 1 : 0; int vidx = type == YUV_YUYV ? 3 : 2; PBYTE pY = pYUV + yidx; PBYTE pV = pYUV + vidx; PBYTE pU = pYUV + uidx; for (int y = 0;y < h;y++) { for (int x = 0;x < w;x++) { Vec3b c = img.at<Vec3b>(y, x); _BGRtoYUV(c, yuv); *pY = yuv[0]; pY+=2; if(x%2==0) { *pU = yuv[1]; *pV = yuv[2]; pU+=4; pV+=4; } } } } break; case YUV_444: { PBYTE pY = pYUV; PBYTE pU = pYUV + w*h; PBYTE pV = pYUV + w*h*2; for (int y = 0;y < h;y++) { for (int x = 0;x < w;x++) { Vec3b c = img.at<Vec3b>(y, x); _BGRtoYUV(c, yuv); *pY++ = yuv[0]; *pU++ = yuv[1]; *pV++ = yuv[2]; } } } break; } }
还是先来张原图:
void Light(Mat& img, long brightness, long contrast) { float c=(100 + contrast)/100.0f; brightness+=128; int dim(256); Mat lut(1,&dim,CV_8U); for(int i = 0; i < 256; i++) { lut.at<uchar>(i) = saturate_cast<uchar>((i-128)*c + brightness + 0.5f); } LUT(img, lut, img); return; }
void Saturation(Mat& img, int sat) { uchar tableUV[256]; float c=(100 + sat)/100.0f; for(int i = 0; i < 256; i++) { tableUV[i] = saturate_cast<uchar>((i-128)*c + 128.5f); } int w = img.cols; int h = img.rows; int size = GetYUVSize(w, h, YUV_NV12); uchar *pBuffer = new uchar[size]; ImageBGR2YUV(img, pBuffer, YUV_NV12); int temp; for(int i = w*h; i < size; i++) { temp = pBuffer[i]; pBuffer[i] = tableUV[temp]; } ImageYUV2BGR(img, pBuffer, YUV_NV12); delete pBuffer; }
void Hue(Mat& img, int h) { cvtColor(img, img, CV_BGR2HLS); for(int x = 0; x < img.cols; x++) { for(int y = 0; y < img.rows; y++) { Vec3b c = img.at<Vec3b>(y, x); c[0] = (c[0]+h)%256; img.at<Vec3b>(y, x) = c; } } cvtColor(img, img, CV_HLS2BGR); }
case ID_COLOR_NEGATIVE: dst= Scalar(255, 255, 255) - image; break; case ID_COLOR_GRAYSCALE: cvtColor(image, dst, CV_BGR2GRAY); cvtColor(dst, dst, CV_GRAY2BGR); break; case ID_COLOR_THRESHOLD: cvtColor(image, dst, CV_BGR2GRAY); threshold(dst, dst, 100, 255, CV_THRESH_OTSU | CV_THRESH_BINARY_INV); cvtColor(dst, dst, CV_GRAY2BGR);
源码已公开,大家可以一起来完善这个工具。有好的想法也可以Email: [email protected]
http://download.csdn.net/detail/fallingstar08/5747747