今天加入了一些新功能:
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: 2723367319@qq.com
http://download.youkuaiyun.com/detail/fallingstar08/5747747