OPENCV+VS空域图像增强

1 篇文章 0 订阅

对“lena.jpg”变换后的灰度图像进行如下操作:
1) 统计每个灰度级(0-255)的像素点数,并打印显示;
原理:灰度级是表示灰度图像的亮度层次范围,每个灰度级都对应着相应的像素点数
实验步骤:分析实验过程——编写代码——运行——获得实验结果

源代码:

#include <iostream> 
#include "opencv.hpp"  
#include "opencv2/core/core.hpp" 
#include "opencv2/highgui/highgui.hpp"    
//计算图像直方图
class Histogram1D{
private:	
int histSize[1];
float hranges[2];	
const float* ranges[1];
int channels[1];
public:	Histogram1D()	{	
	histSize[0] = 256;	
	hranges[0] = 0.0;	
	hranges[1] = 256.0;		
	ranges[0] = hranges;	
	channels[0] = 0;	}
		cv::Mat getHistogram(const cv::Mat& image)	{		
			cv::Mat hist;		
			cv::calcHist(&image,		
				1,//仅为一个图像的直方图		
				channels,//使用的通道		
				cv::Mat(),//不使用掩码		
				hist,//作为结果的直方图			
				1,//这时一维的直方图		
				histSize,//箱子数量		
				ranges//像素值的范围	
			);		
			return hist;	
		}
}; 
int main(){	
	cv::Mat image = cv::imread("C:\\Users\\15518\\Desktop\\opencv\\lena.jpg", 0);
	cv::imshow("lena", image);
	Histogram1D ch;	
	cv::Mat histo = ch.getHistogram(image);	
	for (int i = 0; i < 256; i++)	{		
		std::cout << "Value " << i << " = " << histo.at<float>(i) << std::endl;
	}	
	cv::waitKey();
}

实验结果:
在这里插入图片描述
2)实现幂律变换,并显示;
原理:幂律变换,又称伽马变换,主要用于图像的校正,将灰度过高或者灰度过低的图片进行修正,增强对比度。
实验步骤:分析实验过程和理解幂律变换公式——编写代码——运行——获得实验结果

源代码:

#include "opencv.hpp" 
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>    
#include <opencv2/imgproc/types_c.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/highgui/highgui_c.h>

#include <iostream>

using namespace cv;
using namespace std;

void MyGammaCorrection(Mat& src, Mat& dst, float fGamma)
{

	// build look up table  
	unsigned char lut[256];
	for (int i = 0; i < 256; i++)
	{
		lut[i] = saturate_cast<uchar>(pow((float)(i / 255.0), fGamma) * 255.0f);
	}

	dst = src.clone();
	const int channels = dst.channels();
	switch (channels)
	{
	case 1:   //灰度图的情况
	{

		MatIterator_<uchar> it, end;
		for (it = dst.begin<uchar>(), end = dst.end<uchar>(); it != end; it++)
			//*it = pow((float)(((*it))/255.0), fGamma) * 255.0;  
			*it = lut[(*it)];

		break;
	}
	case 3:  //彩色图的情况
	{

		MatIterator_<Vec3b> it, end;
		for (it = dst.begin<Vec3b>(), end = dst.end<Vec3b>(); it != end; it++)
		{
			//(*it)[0] = pow((float)(((*it)[0])/255.0), fGamma) * 255.0;  
			//(*it)[1] = pow((float)(((*it)[1])/255.0), fGamma) * 255.0;  
			//(*it)[2] = pow((float)(((*it)[2])/255.0), fGamma) * 255.0;  
			(*it)[0] = lut[((*it)[0])];
			(*it)[1] = lut[((*it)[1])];
			(*it)[2] = lut[((*it)[2])];
		}

		break;

	}
	}
}

int main()
{
	Mat image = imread("C:\\Users\\15518\\Desktop\\opencv\\lena.jpg", 0);
	if (image.empty())
	{
		cout << "Error: Could not load image" << endl;
		return 0;
	}

	Mat dst;
	float fGamma = 5;       //修改Y的大小
	MyGammaCorrection(image, dst, fGamma);

	imshow("原始灰度图", image);
	imshow("y>1的幂律变换图", dst);

	waitKey();

	return 0;
}

实验结果:

(1)Y<1的幂律变换
在这里插入图片描述
(2)Y>1的幂律变换
在这里插入图片描述
3)用双线性插值将图像放到 1.5 倍和缩小 0.8 倍,并显示
原理:双线性插值,又称为双线性内插。在数学上,双线性插值是有两个变量的插值函数的线性插值扩展,其核心思想是在两个方向分别进行一次线性插值
实验步骤:分析实验过程和理解双线性插值——编写代码——运行——获得实验结果

源代码:

#include "opencv.hpp" 
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>    
#include <opencv2/imgproc/types_c.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/highgui/highgui_c.h>

#include <iostream>

using namespace cv;
using namespace std;


//双线性插值

sx,xy -- 缩放因子

void Inter_Linear(cv::Mat& src, cv::Mat& dst, double sx, double sy) {

	int dst_rows = round(sx*src.rows);

	int dst_cols = round(sy*src.cols);

	dst = cv::Mat(dst_rows, dst_cols, src.type());

	for (int i = 0; i < dst.rows; i++) {

		//几何中心对齐

		double index_i = (i + 0.5) / sx - 0.5;

		//防止越界

		if (index_i<0) index_i = 0;

		if (index_i >= src.rows - 1) index_i = src.rows - 2;

		//相邻4*4像素的行(坐标)

		int i1 = floor(index_i);

		int i2 = ceil(index_i);

		//u为得到浮点型坐标行的小数部分

		double u = index_i - i1;

		for (int j = 0; j < dst.cols; j++) {

			//几何中心对齐

			double index_j = (j + 0.5) / sy - 0.5;

			//防止越界

			if (index_j<0) index_j = 0;

			if (index_j >= src.cols - 1) index_j = src.cols - 2;

			//相邻4*4像素的列(坐标)

			int j1 = floor(index_j);

			int j2 = ceil(index_j);

			//v为得到浮点型坐标列的小数部分

			double v = index_j - j1;

			if (src.channels() == 1) {

				//灰度图像

				dst.at<uchar>(i, j) = (1 - u)*(1 - v)*src.at<uchar>(i1, j1) + (1 - u)*v*src.at<uchar>(i1, j2) + u * (1 - v)*src.at<uchar>(i2, j1) + u * v*src.at<uchar>(i2, j2);

			}

			else {

				//彩色图像

				dst.at<cv::Vec3b>(i, j)[0] = (1 - u)*(1 - v)*src.at<cv::Vec3b>(i1, j1)[0] + (1 - u)*v*src.at<cv::Vec3b>(i1, j2)[0] + u * (1 - v)*src.at<cv::Vec3b>(i2, j1)[0] + u * v*src.at<cv::Vec3b>(i2, j2)[0];

				dst.at<cv::Vec3b>(i, j)[1] = (1 - u)*(1 - v)*src.at<cv::Vec3b>(i1, j1)[1] + (1 - u)*v*src.at<cv::Vec3b>(i1, j2)[1] + u * (1 - v)*src.at<cv::Vec3b>(i2, j1)[1] + u * v*src.at<cv::Vec3b>(i2, j2)[1];

				dst.at<cv::Vec3b>(i, j)[2] = (1 - u)*(1 - v)*src.at<cv::Vec3b>(i1, j1)[2] + (1 - u)*v*src.at<cv::Vec3b>(i1, j2)[2] + u * (1 - v)*src.at<cv::Vec3b>(i2, j1)[2] + u * v*src.at<cv::Vec3b>(i2, j2)[2];

			}

		}

	}

}
int main()
{
	Mat image = imread("C:\\Users\\15518\\Desktop\\opencv\\lena1.jpg", 0);
	Mat dst;
	double sx = 0.8;
	double sy = 0.8;
	Inter_Linear(image, dst, sx, sy);
	imshow("原始灰度图", image);
	imshow("双线性插值0.8倍图", dst);
	waitKey();
	return 0;
}

改变缩放因子sx,sy,可以改变缩放比例
实验结果:

(1)双线性插值将图像放到 1.5 倍
在这里插入图片描述
(2)双线性插值将图像放到 0.8 倍
在这里插入图片描述
4)将图像进行直方图均衡化处理,显示图像及其直方图;
原理:直方图均衡化实质上是对图像进行非线性拉伸,重新分配图像象元值,使一定范围内象元值的数量大致相等。
实验步骤:分析实验过程和理解直方图均衡化——编写代码——运行——获得实验结果

源代码:

#include <iostream> 
#include "opencv.hpp"  
#include "opencv2/core/core.hpp" 
#include "opencv2/highgui/highgui.hpp"    

class Histogram1D {
private:	
int histSize[1];	
float hranges[2];	
const float* ranges[1];	
int channels[1]; public:	
	Histogram1D() { 
		histSize[0] = 256;		
		hranges[0] = 0.0;		
		hranges[1] = 256.0;		
		ranges[0] = hranges;	
		channels[0] = 0; 
	}	
	cv::Mat getHistogram(const cv::Mat& image) {
	cv::Mat hist;	
	cv::calcHist(&image,
		1,//仅为一个图像的直方图		
		channels,//使用的通道		
		cv::Mat(),//不使用掩码		
		hist,//作为结果的直方图		
		1,//这时一维的直方图		
		histSize,//箱子数量			
		ranges//像素值的范围		
	);		
	return hist;
	}	
	cv::Mat getHistogramImage(const cv::Mat& image, int zoom = 1)	{	
		cv::Mat hist = getHistogram(image);	
		return getImageofHistogram(hist, zoom); 	
	}	
	static cv::Mat getImageofHistogram(const cv::Mat &hist, int zoom)	{	
		double maxVal = 0;	
		double minVal = 0;		
		cv::minMaxLoc(hist, &minVal, &maxVal, 0, 0); 
		int histSize = hist.rows;		
		cv::Mat histImg(histSize *zoom, histSize *zoom, CV_8U, cv::Scalar(255));
		//设置最高点为90%箱子的个数		
		int hpt = static_cast<int>(0.9*histSize);	
		for (int h = 0; h < histSize; h++)		
		{		
			float binVal = hist.at<float>(h);		
			if (binVal > 0)			{		
				int intensity = static_cast<int>(binVal*hpt / maxVal);	
				cv::line(histImg, cv::Point(h*zoom, histSize*zoom),		
					cv::Point(h*zoom, (histSize - intensity)*zoom),		
					cv::Scalar(0), zoom);	
			}		
		}	
		return histImg;
	}
};
		
int main(){	
	cv::Mat image = cv::imread("C:\\Users\\15518\\Desktop\\opencv\\lena.jpg", 0);
	cv::Mat result;
	equalizeHist(image, result);
	Histogram1D ch;	
	cv::Mat histo = ch.getHistogram(result);
	/*for (int i = 0; i < 256; i++) { 
		std::cout << "Value " << i << " = " << histo.at<float>(i) << std::endl;
	}	*/
	cv::Mat hist = ch.getHistogramImage(result);
	cv::imshow("原图", image);
	cv::imshow("均衡化图像", result);
	cv::imshow("直方图", hist);
	cv::waitKey();
}

实验结果:
在这里插入图片描述
5)分别以 3x3、7x7 模板进行均值滤波(或中值滤波)处理,并显示;
原理:均值滤波是典型的线性滤波算法,它是指在图像上对目标像素给一个模板,该模板包括了其周围的临近像素(以目标像素为中心的周围8个像素,构成一个滤波模板,即去掉目标像素本身),再用模板中的全体像素的平均值来代替原来像素值。
实验步骤:分析实验过程和理解直方图均衡化——编写代码——运行——获得实验结果

源代码:

#include "opencv2/highgui/highgui.hpp" 
#include "opencv2/imgproc/imgproc.hpp" 

using namespace cv;

int main()

{

	//载入原始图
	Mat srcImage = imread("C:\\Users\\15518\\Desktop\\opencv\\lena.jpg", 0);
	//显示原始图
	imshow("原图", srcImage);
	//进行均值滤波操作
	Mat dstImage;
	blur(srcImage, dstImage, Size(7, 7));
	//显示效果图
	imshow("7x7均值滤波效果图", dstImage);
	waitKey(0);
}

调整blur(srcImage, dstImage, Size(7, 7))函数中的Size()可以改变模板大小
实验结果:
(1)3x3 模板进行均值滤波处理的结果
在这里插入图片描述
(2)7x7 模板进行均值滤波处理的结果
在这里插入图片描述
扩展部分
源代码:

#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include<ctime>

using namespace cv;
using namespace std;

//均值滤波

void AverFiltering(const Mat &src, Mat &dst) {

	if (!src.data) return;

	//at访问像素点

	for (int i = 1; i<src.rows; ++i)

		for (int j = 1; j < src.cols; ++j) {

			if ((i - 1 >= 0) && (j - 1) >= 0 && (i + 1)<src.rows && (j + 1)<src.cols) {//边缘不进行处理

				dst.at<uchar>(i, j) = (src.at<uchar>(i, j) + src.at<uchar>(i - 1, j - 1) + src.at<uchar>(i - 1, j) + src.at<uchar>(i, j - 1) +

					src.at<uchar>(i - 1, j + 1) + src.at<uchar>(i + 1, j - 1) + src.at<uchar>(i + 1, j + 1) + src.at<uchar>(i, j + 1) +

					src.at<uchar>(i + 1, j)) / 9;

				
			}

			else {//边缘赋值

				dst.at<uchar>(i, j) = src.at<uchar>(i, j);

			}

		}

}

//图像椒盐化

void salt(Mat &image, int num) {

	if (!image.data) return;//防止传入空图

	int i, j;

	srand(time(NULL));

	for (int x = 0; x < num; ++x) {

		i = rand() % image.rows;

		j = rand() % image.cols;

		image.at<uchar>(i, j) = 255;

	}

}

void main() {

	Mat image = imread("C:\\Users\\15518\\Desktop\\opencv\\lena.jpg",0);
	Mat Salt_Image;
	image.copyTo(Salt_Image);
	salt(Salt_Image, 3000);
	Mat image1(image.size(), image.type());
	Mat image2;
	AverFiltering(Salt_Image, image1);
	blur(Salt_Image, image2, Size(3, 3));//openCV库自带的均值滤波函数
	//imshow("椒盐化图像", Salt_Image);
	imshow("原图", image);
	imshow("自定义均值滤波", image1);
	imshow("openCV自带的均值滤波", image2);
	waitKey();
}


实验结果:
(1)椒盐化图像
在这里插入图片描述
3x3模板进行均值滤波处理的图像
在这里插入图片描述
6)分别使用拉普拉斯算子和 Sobel 算子对图像进行锐化处理,并显示。
使用拉普拉斯算子对图像进行锐化处理的原理:当邻域中心像素灰度低于它所在的领域内其它像素的平均灰度时,此中心像素的灰度应被进一步降低,当邻域中心像素灰度高于它所在的邻域内其它像素的平均灰度时,此中心像素的灰度应被进一步提高,以此实现图像的锐化处理。
实验步骤:分析实验过程和理解拉普拉斯算子——编写代码——运行——获得实验结果

源代码:

#include<opencv2/core/core.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp> 
void sharpen(const cv::Mat image, cv::Mat &result){
	result.create(image.size(), image.type());	
	for(int j = 1; j < image.rows-1; j++)	{	
		const uchar* previous = image.ptr<const uchar>(j-1);
		const uchar* current  = image.ptr<const uchar>(j);	
		const uchar* next     = image.ptr<const uchar>(j+1); 	
		uchar* output = result.ptr<uchar>(j);	
		for(int i = 1; i < image.cols-1; i++)		{		
			//sharpened_pixel = 5*current-left-right-up-down;		
			//cv::saturate_cast用以对计算结果进行截断(0-255)		
			*output++ = cv::saturate_cast<uchar>(			
				5*current[i]-current[i-1]				
				-current[i+1]-previous[i]-next[i]);		
		}
	}	
	result.row(0).setTo(cv::Scalar(0));
	result.row(result.rows-1).setTo(cv::Scalar(0));
	result.col(0).setTo(cv::Scalar(0));	
	result.col(result.cols-1).setTo(cv::Scalar(0));
} 
int main(int argc,char** argv){	
	cv::Mat img = cv::imread(argc == 2 ? argv[1] : "C:\\Users\\15518\\Desktop\\opencv\\lena.jpg", 0);
	cv::Mat result;	
	result.create(img.size(), img.type());	
	sharpen(img, result);
	cv::namedWindow("sharpen");
	cv::namedWindow("img");	
	cv::imshow("img",img);	
	cv::imshow("sharpen", result);
	cv::waitKey(0);
}

使用拉普拉斯算子对图像进行锐化处理的实验结果:
在这里插入图片描述
使用Sobel 算子对图像进行锐化处理的原理:Sobel算子根据像素点上下、左右邻点灰度加权差,在边缘处达到极值这一现象检测边缘。
实验步骤:分析实验过程和理解Sobel算子——编写代码(高斯平滑,转灰度,求梯度xy,振幅图像(合并近似梯度))——运行——获得实验结果

源代码:

#include <opencv2/opencv.hpp>
#include<iostream>
#include<math.h>
#include <string> 
#include<fstream> 
#include <opencv2/imgproc/types_c.h>
using namespace cv;
using namespace std;

int main() {
	Mat src, gaosrc, graysrc, xdst, ydst, dst;
	src = imread("C:\\Users\\15518\\Desktop\\opencv\\lena.jpg");
	//imshow("input", src);
	GaussianBlur(src, gaosrc, Size(3, 3), 0, 0);
	//imshow("gaosioutput", gaosrc);
	cvtColor(gaosrc, graysrc, CV_RGB2GRAY);
	imshow("grayoutput", graysrc);
	Sobel(graysrc, xdst, -1, 1, 0);
	//imshow("xdst", xdst);
	Sobel(graysrc, ydst, -1, 0, 1);
	//imshow("ydst", ydst);
	addWeighted(xdst, 0.5, ydst, 0.5, 1, dst);
	imshow("SOBEL_OUTPUT", dst);
	waitKey(0);
}


使用Sobel 算子对图像进行锐化处理的实验结果:
在这里插入图片描述
应用文献:

https://blog.csdn.net/qinghuaci666/article/details/81737624
https://blog.csdn.net/weixin_40647819/article/details/86601070

  • 6
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值