冈萨雷斯数字图像处理第三章灰度变换与空间滤波算法 c++

3.2一些基本的灰度变换函数

具体有 1、图像反转函数 2、对数变换函数 3、幂次(伽马)变换函数 4、分段线性变换函数(对比拉伸、灰度切割、位图切割)

3.2.1图像反转函数

1.数学原理
灰度级范围【0,L-1】的图像反转: S= L-1 -r r为输入,s为输出。
适用于增强嵌入图像暗色区域的白色或灰色细节,特别是黑色面积占据主导地位时。
图像反转就是黑白颠倒,若像素px= 0,则反转后px=255。公式:反转后的像素a= 255- a
2.实现过程
输入
水平翻转:[1,1,0] ---- [0,1,1]
反转图像 [0,1,1] -----[1,0,0] 0与1互换
输出
3.实现代码 c++
直接访问像素点

	#include <iostream>  
#include <opencv2/opencv.hpp>
#include<opencv2/highgui.hpp>  //图形界面和视频图像处理的头文件图形界面和视频图像处理的头文件。
#include<opencv2/imgproc.hpp>  
using namespace std;
using namespace cv;
int main()
{
	Mat src; //定义图像为矩阵
	int height;
	int width;
	int j;
	int i;
	//载入图片
	src = imread("C://Users//征途//Desktop//vs-cpp//Project1//01.jpg");
	if (!src.data) //判断是否为空
	{
		cout << "could not open or find image." << endl;
		return -1;
	}
	//获取图像信息
	height = src.rows;
	width = src.cols* src.channels(); //列项乘以通道数

	//创建窗口
	namedWindow("src", CV_WINDOW_AUTOSIZE);
	namedWindow("dst", CV_WINDOW_AUTOSIZE);

	//显示图片
	imshow("src", src);
	
	//图像反转
	for (i = 0; i<height; i++)
	{
		for (j = 0; j < width; j++)
		{
			src.at<uchar>(i, j) = 255 - src.at<uchar>(i, j);  // a = 255 - a  每一个像素反转
			//img.at<uchar>(i,j)可以得到坐标为(i,j)点的像素值
		}
	}
	//显示图片
	imshow("dst", src);
	waitKey(0);
	return 0;
}

结果
在这里插入图片描述

3.2.2对数变换函数

1.数学原理
实现图像灰度的压缩和膨胀。将窄带低灰度输入图像值进行拓展映射为宽带输出值。即为拓展灰度级小的暗像素,压缩灰度级大的亮像素。最终实现强调图像低灰度值的效果。
S = C * log(1+r)
2.实现步骤
在程序中使用add(InputArray src1, InputArray src2, OutputArray dst, InputArray mask=noArray(), int dtype=-1)
要实现r+1:add(InputImage,Scalar(1.0),OutputImage);
实现log(r+1):log(InputImage,OutputImage)。

3.代码实现 c++
//基于源图像的方法

#include <iostream>  
#include <opencv2/opencv.hpp>
#include<opencv2/highgui.hpp>  //图形界面和视频图像处理的头文件图形界面和视频图像处理的头文件。
#include<opencv2/imgproc.hpp>  //

using namespace std;
using namespace cv;
Mat logTransform1(Mat src, int c)
{
	src = imread("C://Users//征途//Desktop//vs-cpp//Project1//02.jpg");
	if (src.empty())
		cout << "no data" << endl;
	Mat dst = Mat::zeros(src.size(), src.type());
	add(src, Scalar(1.0), src);  // 计算r+1
	src.convertTo(src, CV_32F); // 转变成32位浮点型
	log(src, dst);
	dst = c * dst;
	//归一化处理
	normalize(dst, dst, 0, 255, NORM_MINMAX);
	convertScaleAbs(dst, dst); //范围内,计算绝对值,并将结果转换为8位。
	imshow("dst", src);
	waitKey(0);
	return dst;
}

3.23 幂次(伽马)变换

1.数学原理
在这里插入图片描述
上面公式中,s为输出8位灰度图,r为输入8位灰度图,c为常数,γ为指数
下面图片中
γ<1时,将γ输入窄范围的暗色输入值映射到较宽范围的输出值,扩大灰度值使得暗色显示更明显
γ>1时,将γ输入窄范围的亮色输入值映射到较宽范围的输出值,压缩灰度值使得亮色显示更明显
幂次变化又称为伽马矫正:指用来校正监视器显示的非线性特点,通过调整γ来实现期望图像
在这里插入图片描述
2.实质
伽马变换的实质就是对每一个像素进行幂函数操作
3.代码实现

#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
using namespace std;
using namespace cv;
int main()
{
	//引入图像
	Mat src, dst;
	src = imread("C://Users//征途//Desktop//vs-cpp//Project1//03.jpg");
	
	//伽马变换
	src.convertTo(src, CV_64F, 1.0 / 255.0); //转化为32位浮点型并归一化处理
	int height = src.rows;
	int width = src.cols;
	dst = cv::Mat::zeros(src.size(), src.type());
	float gamma = 1.5;
	for (int i = 0; i < height; i++)
	{
		for (int j = 0; j < width; j++)
		{
			dst.at<double>(i, j) = std::pow(src.at<double>(i, j), gamma);
		}
	}
	dst.convertTo(dst, CV_8U, 255.0);

	//输出图像
	
	imshow("dst", dst);
	waitKey(0);
	return 0;
}

3.2.4分段线性变化函数

1.对比拉伸在这里插入图片描述

(1)数学原理:低对比度的图像由照明不足、成像传感器动态范围太小、图像获取过程中镜头光圈设置错误引起。对比度拉伸是扩展图像灰度级动态范围的处理,因此可以跨越记录介质和显示装置的全部灰度范围。

图3.10(b)显示了一幅8比特低对比度图像。图3.10©显示了对比拉伸后的效果,得到该效果的参数设置如下:(r1,s1)=(rmin,0)且(r2,s2)=(rmax,L-1),其中rmin和rmax分别为图像中的最小灰度级和最大灰度级。因此,变换函数把灰度级由原范围线性地拉伸到整个范围[0,L-1]。
  图3.10(d)显示了前面定义的(r1,s1)=(m,0)和(r2,s2)=(m,L-1)的阈值处理函数后的结果,其中,m是图像的平均灰度级。
(2)实现原理
Y = aX+b X为输入灰度值,Y为输出灰度值,a b为对比拉伸函数的系数
先将输入灰度值归于0-255,然后再利用公式进行对比度拉伸
(3)实现代码

#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
using namespace std;
using namespace cv;
//定义一个对比度拉伸的函数
Mat Contrast_radio(Mat src)
{
	Mat dst = Mat::zeros(src.size(), src.type());
	int height = src.rows;
	int width = src.cols;
	int min = 0;
	int max = 255;
	for (int i = 0; i < height; i++)
	{
		for (int j = 0; j < width; j++)
		{
			if (src.at<uchar>(i, j) < min)     //src.at<uchar>(i,j)表示第i行第j列的像素点
			{
				min = src.at<uchar>(i, j);
			}
			if (src.at<uchar>(i, j) > max)
			{
				max = src.at<uchar>(i, j);
			}
		}
	}
	//Y = aX+b  X为输入灰度值,Y为输出灰度值,a b为对比拉伸函数的系数
	double a = 255 / (max - min);
	double b = -(a * min);
	double result;
	for (int i = 0; i < height; i++)
	{
		for (int j = 0; j < width; j++)
		{
			result = src.at<uchar>(i, j) * a + b;
			if (result > 255)
			{
				result = 255;
			}
			dst.at<uchar>(i, j) = result;
		}
	}
	return dst;
}
//主函数应用对比度拉伸函数
int main1()
{
	Mat src = imread("C://Users//征途//Desktop//vs-cpp//Project1//03.jpg");
	imshow("src", src);
	Mat dst = Contrast_radio(src);
	imshow("dst", dst);
	waitKey(0);
	return 0;
	}

2.灰度分割
(1)数学原理
两种方法
方法一将所需范围所有灰度值显示为一个值如白色,其他灰度值显示另一个值如黑色
方法二,将所需范围的灰度变亮或者变暗,保持其他灰度级不变
在这里插入图片描述

(2)实现代码

3.比特平面分层–位图切割
(1)数学原理
一幅图像包含256个像素,一个像素有8比特,8bit由8个比特平面组成,0-7,从最低位到最高位;
前两个低阶比特平面贡献精细的灰度细节,后四个高阶比特平面包含视觉重要的数据;
源图像任意一个像素的值,可以由比特平面二进制像素值重建:如原图上194像素点,可以二进制形式分在8比特平面上,11000010.
位图切割就是将一副平面分解成比特平面,可以帮助我们量化图像的比特数的充分性。
在这里插入图片描述
在这里插入图片描述

(2)实现代码

#include<iostream>
#include<opencv2/opencv.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/imgproc.hpp>
#include <math.h>
using namespace std;
using namespace cv;
/***************************
num_bit - 指定bit平面
num_bit = 1~8
num_bit=1,即输出第1个Bit平面
****************************/
void Bitplane_stratification(cv::Mat& src, cv::Mat& B, int num_Bit)
{
	int b[8];  //8个二进制bit位
	if (src.channels() > 1)
		cv::cvtColor(src, src, CV_RGB2GRAY);  //转化为单通道灰色
	B.create(src.size(), src.type());
	for (int i = 0; i < src.rows; i++)
	{
		const uchar*ptr_src = src.ptr<uchar>(i); //uchar*ptr_src定义一个uchar类型的指针变量,指针变量名叫ptr,申请一个指针指向每行第一个像素位置,用来遍历一行像素。
		uchar*ptr_B = B.ptr<uchar>(i);  //将变量地址赋予给指针
		for (int j = 0; j < src.cols; j++)
		{
			num2Binary(ptr_src[j], b);
			ptr_B[j] = b[num_Bit - 1] * 255; //0和1灰度差别太小,乘255便于视觉观察
		}

	}
}
int main(void)
{
	cv::Mat src = cv::imread("C://Users//征途//Desktop//vs-cpp//Project1//02.jpg");
	cv::Mat dst;
	Bitplane_stratification(src, dst, 8); //Bit平面分层

	cv::namedWindow("dst");
	cv::imshow("dst", dst);
	cv::waitKey(0);
}
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值