【发布时间】:2016-03-31 11:44:33
【问题描述】:
我正在尝试用我有限的 OpenCV 知识从天空图像(我从相机/视频中获取)中提取云。
在下面的代码示例中,我将图像拆分为 BGR 等通道,并通过蓝红色通道差异获得灰度图像。然后我在这个灰度图像上设置阈值来创建云区域蒙版(事实上,它给出了天空区域,我将它反转)。经过这些步骤,最后我将蒙版放在实际图像上,根据阈值限制显示真实的云区域。它适用于白色/灰色云层,但不适用于蓝色云层。
cv::Mat ch[3], img_gray, img_element, img_brdiff;
img_element = getStructuringElement(MORPH_RECT, Size(6, 6), Point(6, 6));
img_brdiff = cv::Mat::zeros(img_frame.size(), CV_8UC3);
cv::split(img_frame, ch);
cv::absdiff(ch[2], ch[0], img_brdiff);
cv::threshold(img_brdiff, img_gray, 35, 255, CV_THRESH_BINARY_INV);
cv::morphologyEx(img_gray, img_gray, cv::MORPH_CLOSE, img_element);
//cv::medianBlur(img_gray, img_gray, 3);
img_frame.copyTo(img_final, img_gray);
cv::imshow("in", img_frame);
cv::imshow("out", img_final);
知道如何改进这项技术吗?另外,在第二步中,我需要计算每个云的移动方向。
这是我的图片示例。
更新
在对天空特性(例如 NBRR(归一化蓝红比)、饱和度)进行一些额外检查后,我得到了更好的结果,但在我看来仍然不是最好的……扩展示例代码如下。
const int BINARY_TH = 35;
const double SAT_FIX_TH = 0.3;
const double NBRR_FIX_TH = 0.4;
cv::Mat ch[3], img_gray, img_element, img_brdiff;
img_element = getStructuringElement(MORPH_RECT, Size(6, 6), Point(6, 6));
img_brdiff = cv::Mat::zeros(img_frame.size(), CV_8UC3);
cv::split(img_frame, ch);
cv::absdiff(ch[2], ch[0], img_brdiff);
cv::threshold(img_brdiff, img_gray, BINARY_TH, 255, CV_THRESH_BINARY_INV);
cv::morphologyEx(img_gray, img_gray, cv::MORPH_CLOSE, img_element);
double r, b, g, nbrr, sat;
for(int y = 0; y < img_frame.rows; y++)
{
for(int x = 0; x < img_frame.cols; x++)
{
b = img_frame.at<Vec3b>(y,x)[0];
g = img_frame.at<Vec3b>(y,x)[1];
r = img_frame.at<Vec3b>(y,x)[2];
nbrr = (b - r) / (b + r);
sat = 1.0 - (std::min(b, std::min(g, r)) / std::max(b, std::max(g, r)));
if( nbrr < NBRR_FIX_TH &&
sat < SAT_FIX_TH
)
img_gray.at<uchar>(y, x) = (uchar)255;
}
}
cv::medianBlur(img_gray, img_gray, 3);
img_frame.copyTo(img_final, img_gray);
cv::imshow("in", img_frame);
cv::imshow("out", img_final);
【问题讨论】:
-
你在 opencv 论坛上会有更好的运气 - 这是一个非常广泛的问题,没有一个正确的答案