【OpenCV学习】图像处理:二值化处理、直方图统计及显示、中值滤波、最大值最小值拉伸

  • Post author:
  • Post category:其他

8位灰度图像的二值化处理(阈值与图像均值)

对灰度图像进行处理,设定阈值,则图像中像素点的像素值高于阈值的,像素值变为最大像素值,像素点的像素值低于阈值的,像素值变为最小值。

#include <iostream>
#include <opencv2\highgui\highgui.hpp>
#include<opencv2\imgproc\imgproc.hpp>
#include <opencv2\core\core.hpp>

using namespace std;
using namespace cv;

int main(){
	Mat  img, grayImg, dstImg;
	img = imread("D:\jinji.jpg");
	if (!img.data)
	{
		cout<<"no such file!"<<endl;
		return 0;
	}
	cvtColor(img,grayImg, CV_BGR2GRAY );//彩色图像转变为灰度图像
	imshow("img",img);
	imshow("grayImg",grayImg);

	threshold(grayImg, dstImg, 100, 255, CV_THRESH_BINARY);//对图像进行阈值为100的二值化处理

	imshow("result",dstImg);
	imwrite("jinjigraythres.jpg",dstImg);//保存二值化后的结果

	waitKey();
	return 0;
}

结果如下:
在这里插入图片描述

8位灰度图像的直方图统计及显示

灰度直方图(histogram)是灰度级的函数,描述的是图像中每种灰度级像素的个数,反应图像中每种灰度出现的概率,横坐标是灰度级,纵坐标是灰度级出现的概率。

若图像具有L(通常L=256,即8位灰度级)级灰度,则大小为M*N的灰度图像f(x,y)的灰度直方图hist[0…L-1]可用如下计算获得:

  1. 初始化hist[k]=0;k=0,…,L-1
  2. 统计hist[f(x,y)]++;x=0,…,M-1,y=,…N-1
  3. 归一化hist[f(x,y)]/=M*N

在使用轮廓线确定物体边界时,通过直方图更好的选择边界阈值,进行阈值化处理;对物体与背景有较强对比的景物分割特别有用;简单物体的面积和综合光密度IOD可以通过图像的直方图求得。

在直方图中,横坐标表示图像中各个像素点的灰度级,纵坐标表示具有该灰度级的像素个数

归一化直方图中横坐标表示图像各个像素点的灰度级,纵坐标表示出现这个灰度级的概率,且各灰度级概率和为1。
算法:

  1. 图片灰度化;
  2. 遍历Mat,统计各灰度级的像素个数;
  3. 根据OpenCV画点线函数。
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/core.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main(){
	//载入原图并显示
	Mat srcImage = imread("D:\jinji.jpg",0);
	imshow("srcImage",srcImage);
	if (!srcImage.data)
	{
		cout<<"no such file!";
		return 0;
	}

	//定义变量
	MatND dstHist;
	int dims = 1;
	float hranges[] ={0,255};
	const float *ranges[] = {hranges};
	int size=256;
	int channels = 0;

	//计算图像的直方图
	calcHist(&srcImage, 1, &channels, Mat(), dstHist, dims, &size, ranges);
	int scale =1;

	Mat dstImage(size*scale, size, CV_8U, Scalar(0));

	//获取最大值和最小值
	double minValue = 0;
	double maxValue=0;
	minMaxLoc(dstHist,&minValue,&maxValue,0,0);

	//绘制出直方图
	int hpt = saturate_cast<int>(0.9*size);
	for (int i=0;i<256;i++)
	{
		float binValue = dstHist.at<float>(i);
		int realValue = saturate_cast<int>(binValue*hpt/maxValue);
		rectangle(dstImage,Point(i*scale,size-1),Point((i+1)*scale-1,size-realValue),Scalar(255));
	}
	imshow("一维直方图",dstImage);
	waitKey(0);
	return 0;
}

结果如下:
在这里插入图片描述
直方图Hist
在这里插入图片描述

24位彩色图像直方图统计

算法:

  1. 对三个颜色通道分别进行统计;
  2. 对三色颜色通道分别进行绘制.
#include <opencv2/opencv.hpp>  
#include <opencv2/imgproc/imgproc.hpp>  
using namespace cv;  

int main(  )
{

	//【1】载入素材图并显示
	Mat srcImage;
	srcImage=imread("D:\jinji.jpg");
	imshow( "素材图", srcImage );

	system("color 3F");
	ShowHelpText();

	//【2】参数准备
	int bins = 256;
	int hist_size[] = {bins};
	float range[] = { 0, 256 };
	const float* ranges[] = { range};
	MatND redHist,grayHist,blueHist;
	int channels_r[] = {0};

	//【3】进行直方图的计算(红色分量部分)
	calcHist( &srcImage, 1, channels_r, Mat(), //不使用掩膜
		redHist, 1, hist_size, ranges,
		true, false );

	//【4】进行直方图的计算(绿色分量部分)
	int channels_g[] = {1};
	calcHist( &srcImage, 1, channels_g, Mat(), // do not use mask
		grayHist, 1, hist_size, ranges,
		true, // the histogram is uniform
		false );

	//【5】进行直方图的计算(蓝色分量部分)
	int channels_b[] = {2};
	calcHist( &srcImage, 1, channels_b, Mat(), // do not use mask
		blueHist, 1, hist_size, ranges,
		true, // the histogram is uniform
		false );

	//-----------------------绘制出三色直方图------------------------
	//参数准备
	double maxValue_red,maxValue_green,maxValue_blue;
	minMaxLoc(redHist, 0, &maxValue_red, 0, 0);
	minMaxLoc(grayHist, 0, &maxValue_green, 0, 0);
	minMaxLoc(blueHist, 0, &maxValue_blue, 0, 0);
	int scale = 1;
	int histHeight=256;
	Mat histImage = Mat::zeros(histHeight,bins*3, CV_8UC3);

	//正式开始绘制
	for(int i=0;i<bins;i++)
	{
		//参数准备
		float binValue_red = redHist.at<float>(i); 
		float binValue_green = grayHist.at<float>(i);
		float binValue_blue = blueHist.at<float>(i);
		int intensity_red = cvRound(binValue_red*histHeight/maxValue_red);  //要绘制的高度
		int intensity_green = cvRound(binValue_green*histHeight/maxValue_green);  //要绘制的高度
		int intensity_blue = cvRound(binValue_blue*histHeight/maxValue_blue);  //要绘制的高度

		//绘制红色分量的直方图
		rectangle(histImage,Point(i*scale,histHeight-1),
			Point((i+1)*scale - 1, histHeight - intensity_red),
			Scalar(255,0,0));

		//绘制绿色分量的直方图
		rectangle(histImage,Point((i+bins)*scale,histHeight-1),
			Point((i+bins+1)*scale - 1, histHeight - intensity_green),
			Scalar(0,255,0));

		//绘制蓝色分量的直方图
		rectangle(histImage,Point((i+bins*2)*scale,histHeight-1),
			Point((i+bins*2+1)*scale - 1, histHeight - intensity_blue),
			Scalar(0,0,255));

	}

	//在窗口中显示出绘制好的直方图
	imshow( "图像的RGB直方图", histImage );
	waitKey(0);
	return 0;
}

结果如下:
在这里插入图片描述
直方图
在这里插入图片描述

中值滤波

取目标像素点的NN的邻域,将邻域中的灰度值进行排序,取位于中间的值作为目标像素点的灰度值,也可以代替所有值,这样可以去除掉区域中的最大值和最小值。因此,中值滤波被称为统计排序滤波器,功能上对椒盐噪声有很好的抑制作用。缺点就是需要的计算时间长,是均值滤波的5倍。计算方法,1.假设以33为例,取周边的点从小到大进行排序;2.取中间值,一般是取奇数点的值作为中值,若为偶数个值进行排序,则取中间两个数的平均值。
函数说明:

void medianBlur(InputArray src, OutputArray dst, int ksize);
  • src为原图像,Mat类型图像;
  • dst为目标图像;
  • 卷积核的大小,必须大于等于1,且为奇数,值越大,滤波效果越强;
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

using namespace cv;

int main(){
	//载入图像
	Mat image=imread("D:\jinji.jpg");
	//创建窗口
	namedWindow("srcImage");
	namedWindow("dstImage");
	//显示原图
	imshow("srcImage",image);
	//进行中值滤波
	Mat dst;
	medianBlur(image,dst,3);
	//显示滤波结果
	imshow("dstImage",dst);
	waitKey(0);
	return 0;
}

最大值最小值拉伸

找出灰度图像中灰度值的最大值和最小值,函数如下:

void minMaxLoc(InputArray src, CV_OUT double* minVal, CV_OUT double* maxVal /* = 0 */, CV_OUT Point* minLoc /* = 0 */, CV_OUT Point* maxLoc /* = 0 */, InputArray mask /* = noArray() */)
  • src 原图像
  • minVal 指向最小值的指针,未指定则为NULL
  • maxVal 指向最大值的指针,未指定则为NULL
  • minLoc 指向最小值位置(2维情况)的指针,未指定则为NULL
  • maxLoc 指向最大值位置(2维情况) 的指针,未指定则为NULL
  • mask 可选的蒙版,用于选择待处理子区域

程序如下:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main(){
	Mat src = imread("D:\jinji.jpg",0);
	imshow("original image", src);

	double minVal = 0 ,maxVal = 0;
	cv::Point minPt,maxPt;
	minMaxLoc(src, &minVal, &maxVal, &minPt, &maxPt);
	cout<<"min value ="<<minVal<<endl;
	cout<<"max value ="<<maxVal<<endl;
	cout<<"minPt = ("<<minPt.x<<","<<minPt.y<<")"<<endl;
	cout<<"maxPt = ("<<maxPt.x<<","<<maxPt.y<<")"<<endl;
	cout<<endl;

	cv::Rect rectMin(minPt.x-10,minPt.y-10,20,20);
	cv::Rect rectMax(maxPt.x-10,maxPt.y-10,20,20);

	cv::rectangle(src,rectMin,cv::Scalar(200),2);
	cv::rectangle(src,rectMax,cv::Scalar(200),2);

	imshow("image with min max location",src);
	cv::waitKey();

	return 0;

}

图像拉伸是最基础的图像处理方法,主要用于改善图像显示的对比度,道路提取流程中首先对图像进行拉伸的预处理。图像拉伸主要有三种方式:灰度拉伸、直方图均衡化和直方图规定化。
灰度拉伸:
灰度拉伸以像素为单位对图像进行增强,对指定的灰度范围进行变换。因为像素的灰度值和地物具有相应的关系,所以灰度拉伸可以用来突出或者抑制指定地物的特征,这也要起对地物灰度的分布有一定认识。灰度拉伸主要有三种方式:线性拉伸、非线性拉伸和多波段拉伸。

线性拉伸
全域线性拉伸:大部分像素灰度分布在[a,b]时,可将[a,b]拉伸到[c,d],常用方法。
多分担线性拉伸:突出目标地物灰度区间,抑制不感兴趣的其他区间。
分段窗口切片(Slicing):将某一区间灰度级与其他部分(即背景)区分开来。

非线性拉伸:非线性,包括指数函数、对数函数、平方根、高斯函数等。
指数变换:高灰度区(亮的部分)扩大了灰度间隔,突出细节;低灰度区(暗的部分)缩小灰度间隔,弱化细节。
对数变换:低灰度区较大拉伸、高灰度区压缩,使图像灰度分布与人的视觉特性匹配。

多波段拉伸:对各个波段分别进行线性拉伸或非线性拉伸,综合增强图像显示的地物信息。


版权声明:本文为weixin_42415138原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。