由于一些特殊原因,需要将色差图显示在Qt绘制的软件界面中。由于调用matlab编译动态库的运行效率较低,因此采用OpenCV提供的绘图与注释功能来绘制色差图。其最终效果如图1所示,图中camera数据由imx347模组拍摄的X-Rite 24色卡,在经过简单的去马赛克和白平衡处理后得到的数据值;而idea数据则为CIE标准值。
函数 | 描述 |
---|---|
cv::circle() | 画一个简单的圆 |
cv::line() | 画一条简单的直线 |
cv::rectangle() | 画一个简单的矩形 |
cv::putText() | 在图像中绘制指定的文字 |
关于绘制色差图,主要经过了以下步骤:
- 准备Camera数据,并将数据从rgb域转换到lab域;
- 绘制色差图背景;
- 绘制camera、idea数据点,并将数据点连线,打印色卡块序号;
- 添加camera、idea图例;
1. 准备数据,并将数据从rgb域转换到lab域。在此仅给出rgb转lab域的函数,并未给出具体的色块数据。
/*
描述: rgb -> lab
输入:存储rgb信息的矩阵(24 * 3)
输出:L, a, b数据值
*/
void rgb2lab(Mat src, Mat *L, Mat *a, Mat *b)
{
Mat rgbchannel[3], labchannel[3], rgb, lab;
rgbchannel[0] = src.colRange(0, 1).clone();
rgbchannel[1] = src.colRange(1, 2).clone();
rgbchannel[2] = src.colRange(2, 3).clone();
// rgb——>lab
merge(rgbchannel, 3, rgb);
cvtColor(rgb, lab, COLOR_RGB2Lab);
split(lab, labchannel);
(*L) = labchannel[0].clone();
(*a) = labchannel[1].clone();
(*b) = labchannel[2].clone();
}
2. 绘制色差图背景。
/*
描述:与matlab meshgrid功能相同
*/
void meshgrid(const Range xr, const Range yr, float step, Mat &outX, Mat &outY)
{
vector<float> x, y;
for (float i = xr.start; i <= xr.end; i += step)
x.push_back(i);
for (float i = yr.start; i <= yr.end; i += step)
y.push_back(i);
repeat(Mat(x).t(), y.size(), 1, outX);
repeat(Mat(y), 1, x.size(), outY);
}
/*
描述:生成色差图背景
返回:色差图背景
*/
Mat createBackground()
{
Mat a, b, lab, rgb, channel[3];
// 准备数据
meshgrid(Range(-80, 100), Range(-80, 120), 0.1, a, b); // 生成网格
Mat L = Mat::ones(a.size(), CV_32FC1);
L = L.mul(90);
L.row(800) = 50;
L.col(800) = 50;
a.convertTo(a, CV_32FC1);
b.convertTo(b, CV_32FC1);
// 生成背景
channel[0] = L;
channel[1] = a;
channel[2] = b;
merge(channel, 3, lab);
cvtColor(lab, rgb, COLOR_Lab2BGR);
flip(rgb, rgb, 0);
return rgb;
}
3. 绘制camera、idea数据点,并将数据点连线,打印色卡块序号;
for (int i = 0; i < 24; i++)
{
// 指定颜色
float colorR = target.at<float>(i, 0);
float colorG = target.at<float>(i, 1);
float colorB = target.at<float>(i, 2);
// 绘制idea数据点
int ix = calculateCoordinate((int)ideaa.at<float>(i, 0), Range(-80, 100));
int iy = calculateCoordinate((int)ideab.at<float>(i, 0), Range(-80, 120));
cv::Point ipoint;
ix = ix * 10;
iy = 2001 - iy * 10;
ipoint.x = ix;
ipoint.y = iy;
circle(rgb, ipoint, 11, Scalar(0.4, 0.4, 0.4), 3, LINE_AA);
circle(rgb, ipoint, 10, Scalar(colorB, colorG, colorR), -1, LINE_AA);
// 绘制camera数据值
int cx = calculateCoordinate((int)curta.at<float>(i, 0), Range(-80, 100));
int cy = calculateCoordinate((int)curtb.at<float>(i, 0), Range(-80, 120));
cx = cx * 10;
cy = 2001 - cy * 10;
cv::Point cpoint;
cpoint.x = cx;
cpoint.y = cy;
Rect rectedge = Rect(cx - 9, cy - 9, 17, 17);
Rect rect = Rect(cx - 8, cy - 8, 15, 15);
rectangle(rgb, rectedge, Scalar(0.4, 0.4, 0.4), 3, LINE_AA);
rectangle(rgb, rect, Scalar(colorB, colorG, colorR), -1, LINE_AA);
// 连接idea值与camera数据值
line(rgb, ipoint, cpoint, Scalar(colorB, colorG, colorR), 5, LINE_AA);
// 打印色卡块序号
string numlable = to_string(i+1);
int x = (ix + cx) / 2;
int y = (iy + cy) / 2;
putText(rgb, numlable, Point(x, y), FONT_HERSHEY_DUPLEX, 1, Scalar(0, 0, 0), 1, LINE_AA);
}
由于背景是以Mat形式存储,因此在绘制数据点时,需要将a, b的值转换成Mat的横纵坐标。其转换函数如下
int calculateCoordinate(int value, const Range range)
{
int count = 0;
for (int i = range.start; i < range.end; i++)
{
if (value == i)
return count;
count++;
}
return -1;
}
4. 添加camera、idea图例。
// 打印camera值图例
Rect camera = Rect(150 - 10, 100 - 10, 20, 20);
rectangle(rgb, camera, Scalar(0.4, 0.4, 0.4), -1, LINE_AA);
string camerastr = "camera";
putText(rgb, camerastr, Point(170, 105), FONT_HERSHEY_DUPLEX, 1, Scalar(0, 0, 0), 1, LINE_AA);
// 打印理想值图例
circle(rgb, Point(150, 150), 11, Scalar(0.4, 0.4, 0.4), -1, LINE_AA);
string ideastr = "idea";
putText(rgb, ideastr, Point(170, 160), FONT_HERSHEY_DUPLEX, 1, Scalar(0, 0, 0), 1, LINE_AA);
说明:
上述代码,采用VS2013+OpenCV3.0环境编译,且验证通过。使用者可自行准备camera和idea的数据进行验证。图1所示的色差图中,并未打印色差相关的信息,若有人使用源码,可根据自己的需求添加色差信息。
个人声明:
以上内容,纯属个人观点,不喜勿喷。未经本人同意,不得私自转载。博客中出现的代码仅供学习参考,不得有其他用途。若文中存在纰漏,或读者有更好的建议,欢迎留言探讨。也可邮箱联系:yxyx_0212@163.com