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]可用如下计算获得:
- 初始化hist[k]=0;k=0,…,L-1
- 统计hist[f(x,y)]++;x=0,…,M-1,y=,…N-1
- 归一化hist[f(x,y)]/=M*N
在使用轮廓线确定物体边界时,通过直方图更好的选择边界阈值,进行阈值化处理;对物体与背景有较强对比的景物分割特别有用;简单物体的面积和综合光密度IOD可以通过图像的直方图求得。
在直方图中,横坐标表示图像中各个像素点的灰度级,纵坐标表示具有该灰度级的像素个数。
归一化直方图中横坐标表示图像各个像素点的灰度级,纵坐标表示出现这个灰度级的概率,且各灰度级概率和为1。
算法:
- 图片灰度化;
- 遍历Mat,统计各灰度级的像素个数;
- 根据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位彩色图像直方图统计
算法:
- 对三个颜色通道分别进行统计;
- 对三色颜色通道分别进行绘制.
#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):将某一区间灰度级与其他部分(即背景)区分开来。
非线性拉伸:非线性,包括指数函数、对数函数、平方根、高斯函数等。
指数变换:高灰度区(亮的部分)扩大了灰度间隔,突出细节;低灰度区(暗的部分)缩小灰度间隔,弱化细节。
对数变换:低灰度区较大拉伸、高灰度区压缩,使图像灰度分布与人的视觉特性匹配。
多波段拉伸:对各个波段分别进行线性拉伸或非线性拉伸,综合增强图像显示的地物信息。