我必须实现两种算法来转换BGR <-> HSI,而无需使用OpenCV例程。我按照《数字图像处理》 (冈萨雷斯-伍兹)和this topic中的公式正确实现了BGR2HSI算法:
#define rad(x) (x * M_PI / 180.0)
#define deg(x) (x * 180.0 / M_PI)
Mat BGR2HSI(Mat src) {
Mat out = Mat::zeros(src.rows, src.cols, src.type());
for (int i = 0; i < src.rows; i++)
for (int j = 0; j < src.cols; j++) {
double b = src.at<Vec3b>(i,j)[0]; // B (blu)
double g = src.at<Vec3b>(i,j)[1]; // G (green)
double r = src.at<Vec3b>(i,j)[2]; // R (red)
double theta = (b != 0 && g != 0 && r != 0) ? deg(acos(0.5 * ((r-g) + (r-b)) / sqrt((pow(r-g,2)) + ((r-b)*(g-b))))) : 0;
out.at<Vec3b>(i,j)[0] = (b <= g) ? theta : 360 - theta; // H (hue)
out.at<Vec3b>(i,j)[1] = (b != 0 && g != 0 && r != 0) ? (1.0 - 3*(min(min(b,g),r)/(b + g + r))) * 100 : 0; // S (saturation)
out.at<Vec3b>(i,j)[2] = (b + g + r) / 3; // I (intensity)
}
return out;
}
我对此算法有疑问:我不知道为什么必须将饱和度公式乘以100。此外,我定义了rad()
和deg()
函数,因为我知道cmath
例程使用辐射,但是似乎OpenCV使用度数,如果我做错了,请更正。
另一方面,我仍然遵循本书的公式编写了此HSI2BGR函数,但它不起作用:
Mat HSI2BGR(Mat src) {
Mat out = Mat::zeros(src.size(), src.type());
for (int i = 0; i < src.rows; i++)
for (int j = 0; j < src.cols; j++) {
double H = src.at<Vec3b>(i,j)[0]; // componente H
double S = src.at<Vec3b>(i,j)[1]; // componente S
double I = src.at<Vec3b>(i,j)[2]; // componente I
H *= 360;
if (H >= 240 && H < 360) {
H -= 240;
double g = out.at<Vec3b>(i,j)[1] = I * (1.0 - S); // green
double b = out.at<Vec3b>(i,j)[0] = I * (1.0 + (S * deg(cos(rad(H))))/(deg(cos(rad(60 - H))))); // blu
out.at<Vec3b>(i,j)[2] = 31 - (g + b); // red
}
else
if (H >= 120 && H < 240) {
H -= 120;
double r = out.at<Vec3b>(i,j)[2] = I * (1.0 - S); // red
double g = out.at<Vec3b>(i,j)[1] = I * (1.0 + (S * deg(cos(rad(H))))/(deg(cos(rad(60 - H))))); // green
out.at<Vec3b>(i,j)[0] = 31 - (r + g); // blu
}
else {
double b = out.at<Vec3b>(i,j)[0] = I * (1.0 - S); // blu
double r = out.at<Vec3b>(i,j)[2] = I * (1.0 + (S * deg(cos(rad(H))))/(deg(cos(rad(60 - H))))); // red
out.at<Vec3b>(i,j)[1] = 31 - (r + b); // green
}
}
return out;
}