Bootstrap

遥感图像处理-阴影提取

     最近在做一个遥感图像处理的任务,觉得比较有意思,就拿出来跟大家分享一下。

     这次的任务是遥感图像的阴影提取,看上去好像有一点高大上的样子,让人有些摸不到头脑。我先到网上查找了一下,主要的方法都是用二值化,配合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;
}

   

 

;