最近在做一个遥感图像处理的任务,觉得比较有意思,就拿出来跟大家分享一下。
这次的任务是遥感图像的阴影提取,看上去好像有一点高大上的样子,让人有些摸不到头脑。我先到网上查找了一下,主要的方法都是用二值化,配合Canny算子或者Sobel算子之类的来提取阴影的面积,但是我觉得这样做比较复杂,而且效果也不一定很好。于是我就变了一个思路,来用阴影本身的特点来进行提取。
首先要说明的是,我要处理的图像都是光照条件比较好的,所以阴影部分的亮度就会比其他区域的亮度明显低不少;另外,由于亮度的降低,导致其色调比较浅,所以R、G、B三个通道数值的方差肯定比较小。为了编写代码,我先做了一些尝试,最后确定了效果比较好的阈值,最后计算了阴影面积的比重,并显示在窗口的标题上。
下面我们来看一下效果
原图
阴影图
最终效果图 强力提取效果图
从图中可以看到,最终的效果还是非常好的,目测估计准确率在90%以上(哈哈哈)
下面是其他图片的处理效果
无论是遥感影像还是生活照的效果都不错哦。
下面就是代码部分了。(提醒:环境是VS2017+OPENCV4.1)
大家有什么好的办法,记得和我讨论分享一下哦。(^_^)
#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>
#include <math.h>
using namespace std;
using namespace cv;
double varOf3(double x1, double x2, double x3) {
double mean = (x1 + x2 + x3) / 3;
return (pow((x1 - mean), 2) + pow((x2 - mean), 2) + pow((x3 - mean), 2));
}
Mat ShadowExtraction(Mat src,int type=1);
int main()
{
//读取图片
char filename[] = "Color4.bmp";
Mat src = imread(filename);
resize(src, src, Size(720, (720 * src.rows / src.cols)));//将图像的尺寸缩放到适合屏幕观看
imshow("Previous", src);
ShadowExtraction(src);
return 0;
}
Mat ShadowExtraction(Mat src, int type ) {
int rows = src.rows, cols = src.cols;
Mat M(rows, cols, CV_8UC1);
double* var = new double[rows*cols];
int i = 0;
for (int x = 0; x < cols; x++) {
for (int y = 0; y < rows; y++) {
if (((double)src.at<Vec3b>(y, x)[0] + (double)src.at<Vec3b>(y, x)[1] + (double)src.at<Vec3b>(y, x)[2]) < 250) {//限制亮度
var[i] = sqrt(varOf3((double)src.at<Vec3b>(y, x)[0], (double)src.at<Vec3b>(y, x)[1], (double)src.at<Vec3b>(y, x)[2]));
}
else {
var[i] = 255;
}
i++;
}
}
int j = 0;
for (int x = 0; x < cols; x++) {
for (int y = 0; y < rows; y++) {
M.at<uchar>(y, x) = (uchar)(var[j]);//把方差作为亮度进行赋值
j++;
}
}
//imshow("Before Binarization", M);
switch (type) {
case 1://轻度阴影提取
equalizeHist(M, M);//可以过滤掉颜色比较浅的部分
break;
case 2://强力阴影提取
break;
}
/*int block_size = 25;
int const_value = 10;
adaptiveThreshold(M, M, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, block_size, const_value);*/
threshold(M, M, 70, 255, THRESH_BINARY_INV);//把图像二值化
medianBlur(M, M, 7);//中值滤波,去除小斑点
imshow("Shadow", M);
Mat M3 = src.clone();//M3是最后阴影提取后的结果
double count = 0.0;
for (int x = 0; x < cols; x++) {//给识别出来的阴影上色
for (int y = 0; y < rows; y++) {
if (M.at<uchar>(y, x) == 255) {
M3.at<Vec3b>(y, x)[0] = 255;
M3.at<Vec3b>(y, x)[1] = 0;
M3.at<Vec3b>(y, x)[2] = 0;
count++;
}
}
}
char str1[64] = "Shadow in Previous";
char str2[64];
sprintf_s(str2, " || Weight of Shadow:%.2lf%%", 100.0*count / rows / cols);//阴影量
strcat_s(str1, str2);
//erode(M3, M3, Mat());//腐蚀
//dilate(M3, M3, Mat());//膨胀
imshow(str1, M3);//显示最后处理结果的
waitKey(0);
delete[] var;
return M3;
}