基于opencv的c++图像处理(灰度变换)

前言

基于opencv的c++接口,实现常用的图像灰度变换方法,包括了线性变换、图像反转、对数变换和伽马变换。

相关的opencv接口解析

CV_EXPORTS_W void normalize( InputArray src, InputOutputArray dst, double alpha = 1, double beta = 0,
                             int norm_type = NORM_L2, int dtype = -1, InputArray mask = noArray());

函数 cv::normalize 标准化缩放和移动输入数组元素
当 normType=NORM_MINMAX 时(仅适用于密集数组)。可选掩码指定要规范化的子数组。这意味着在子数组上计算范数或 min-n-max,然后修改该子数组以进行归一化。如果您只想使用掩码计算范数或最小值-最大值但修改整个数组,则可以使用 norm 和 Mat::convertTo。
@param src 输入数组。
@param dst 与 src 大小相同的输出数组。
@param alpha norm value 规范化到或范围归一化情况下的范围下限。
@param beta 范围归一化情况下的范围上限;它不用于规范标准化。
@param norm_type 规范化类型(参见 cv::NormTypes)。
@param dtype 为负时,输出数组与 src 类型相同;否则,它具有与 src 相同数量的通道和深度 =CV_MAT_DEPTH(dtype)。
@param mask 可选操作掩码。

enum NormTypes {
    
    
                /**
                \f[
                norm =  \forkthree
                {\|\texttt{src1}\|_{L_{\infty}} =  \max _I | \texttt{src1} (I)|}{if  \(\texttt{normType} = \texttt{NORM_INF}\) }
                {\|\texttt{src1}-\texttt{src2}\|_{L_{\infty}} =  \max _I | \texttt{src1} (I) -  \texttt{src2} (I)|}{if  \(\texttt{normType} = \texttt{NORM_INF}\) }
                {\frac{\|\texttt{src1}-\texttt{src2}\|_{L_{\infty}}    }{\|\texttt{src2}\|_{L_{\infty}} }}{if  \(\texttt{normType} = \texttt{NORM_RELATIVE | NORM_INF}\) }
                \f]
                */
                NORM_INF       = 1,
                /**
                \f[
                norm =  \forkthree
                {\| \texttt{src1} \| _{L_1} =  \sum _I | \texttt{src1} (I)|}{if  \(\texttt{normType} = \texttt{NORM_L1}\)}
                { \| \texttt{src1} - \texttt{src2} \| _{L_1} =  \sum _I | \texttt{src1} (I) -  \texttt{src2} (I)|}{if  \(\texttt{normType} = \texttt{NORM_L1}\) }
                { \frac{\|\texttt{src1}-\texttt{src2}\|_{L_1} }{\|\texttt{src2}\|_{L_1}} }{if  \(\texttt{normType} = \texttt{NORM_RELATIVE | NORM_L1}\) }
                \f]*/
                 NORM_L1        = 2,
                 /**
                 \f[
                 norm =  \forkthree
                 { \| \texttt{src1} \| _{L_2} =  \sqrt{\sum_I \texttt{src1}(I)^2} }{if  \(\texttt{normType} = \texttt{NORM_L2}\) }
                 { \| \texttt{src1} - \texttt{src2} \| _{L_2} =  \sqrt{\sum_I (\texttt{src1}(I) - \texttt{src2}(I))^2} }{if  \(\texttt{normType} = \texttt{NORM_L2}\) }
                 { \frac{\|\texttt{src1}-\texttt{src2}\|_{L_2} }{\|\texttt{src2}\|_{L_2}} }{if  \(\texttt{normType} = \texttt{NORM_RELATIVE | NORM_L2}\) }
                 \f]
                 */
                 NORM_L2        = 4,
                 /**
                 \f[
                 norm =  \forkthree
                 { \| \texttt{src1} \| _{L_2} ^{2} = \sum_I \texttt{src1}(I)^2} {if  \(\texttt{normType} = \texttt{NORM_L2SQR}\)}
                 { \| \texttt{src1} - \texttt{src2} \| _{L_2} ^{2} =  \sum_I (\texttt{src1}(I) - \texttt{src2}(I))^2 }{if  \(\texttt{normType} = \texttt{NORM_L2SQR}\) }
                 { \left(\frac{\|\texttt{src1}-\texttt{src2}\|_{L_2} }{\|\texttt{src2}\|_{L_2}}\right)^2 }{if  \(\texttt{normType} = \texttt{NORM_RELATIVE | NORM_L2SQR}\) }
                 \f]
                 */
                 NORM_L2SQR     = 5,
                 /**
                 In the case of one input array, calculates the Hamming distance of the array from zero,
                 In the case of two input arrays, calculates the Hamming distance between the arrays.
                 */
                 NORM_HAMMING   = 6,
                 /**
                 Similar to NORM_HAMMING, but in the calculation, each two bits of the input sequence will
                 be added and treated as a single bit to be used in the same calculation as NORM_HAMMING.
                 */
                 NORM_HAMMING2  = 7,
                 NORM_TYPE_MASK = 7, //!< bit-mask which can be used to separate norm type from norm flags
                 NORM_RELATIVE  = 8, //!< flag
                 NORM_MINMAX    = 32 //!< flag
               };
CV_EXPORTS_W void convertScaleAbs(InputArray src, OutputArray dst,
                                  double alpha = 1, double beta = 0);

函数可用于缩放,计算绝对值,并将结果转换为 8 位。
在输入数组的每个元素上,函数 convertScaleAbs 依次执行三个操作:缩放、取绝对值、转换为无符号 8 位类型。
在多通道数组的情况下,该函数独立处理每个通道。当输出不是 8 位时,可以通过调用 Mat::convertTo 方法(或使用矩阵表达式)模拟该操作,然后计算结果的绝对值。
@param src 输入数组。
@param dst 输出数组。
@param alpha 可选比例因子。
@param beta 可选增量添加到缩放值。

常用灰度变换公式

图像反转公式:s=255-r,其中,r表示原始图像的灰度级,s表示变换后的灰度级。
对数变换公式:s=clog(1+r),其中,r表示原始图像的灰度级,s表示变换后的灰度级,c为常数。
伽马变换公式:s=c
r^y,其中,r表示原始图像的灰度级,s表示变换后的灰度级,c为比例系数,y为幂数。
线性变换公式:s=a*r+b,其中,r表示原始图像的灰度级,s表示变换后的灰度级,a为比例系数,b为平移系数。

示例代码

grayTransform.h

#pragma once

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

using namespace std;
using namespace cv;
#define PROCESS_IMG_SUCESS 0
#define PROCESS_IMG_FAIL 1


namespace ImgEnhance
{
    
    
	//灰度变换
	class GrayscaleTransform
	{
    
    

	public:
		GrayscaleTransform() {
    
     cout << "GrayscaleTransform is being created" << endl; } // 这是构造函数声明
		~GrayscaleTransform() {
    
     cout << "GrayscaleTransform is being deleted" << endl; } // 这是析构函数声明

		int ImageInverse(cv::Mat srcImage, cv::Mat &dstImage);//图像反转//灰度线性变换最常见的就是图像反转:s=255-r
		int ImageLogTransform(cv::Mat srcImage, cv::Mat &dstImage,float c);//对数变换//s=c*log(1+r):其中,r表示原始图像的灰度级,s表示变换后的灰度级,c为常数。
		int ImageGammaTransform(cv::Mat srcImage, cv::Mat &dstImage, float c,float y);//伽马变换//s=c*r^y
		int ImageLinearTransform(cv::Mat srcImage, cv::Mat &dstImage, float a, float b);//线性变换//s=a*r+b

	};

}

grayTransform.cpp

#include"grayTransform.h"

int ImgEnhance::GrayscaleTransform::ImageInverse(cv::Mat srcImage, cv::Mat &dstImage)//图像反转
{
    
    
	if (!srcImage.data || srcImage.channels() != 1)
	{
    
    
		return 1;
	}
	int height = srcImage.rows;
	int width = srcImage.cols;
	
	Mat dst = Mat(height, width,CV_8UC1);
	for (int i = 0; i < height; i++)
	{
    
    
		uchar* p1 = dst.ptr<uchar>(i);
		uchar* p2 = srcImage.ptr<uchar>(i);
		for (int j = 0; j < srcImage.cols; j++)
		{
    
    
			p1[j] = 255 - p2[j];
		}
	}

	dstImage = dst.clone();

	return 0;
}

int ImgEnhance::GrayscaleTransform::ImageLogTransform(cv::Mat srcImage, cv::Mat &dstImage, float c)//对数变换//s=c*log(1+r)
{
    
    
	if (!srcImage.data || srcImage.channels() != 1)
	{
    
    
		return 1;
	}
	int height = srcImage.rows;
	int width = srcImage.cols;

	float pixels[256];
	for (int i = 0; i < 256; i++)
	{
    
    
		pixels[i] = c*log(1 + i);
	}
		
	Mat imageLog(height, width, CV_32FC1);
	for (int i = 0; i<height; i++)
	{
    
    
		float* p1 = imageLog.ptr<float>(i);
		uchar* p2 = srcImage.ptr<uchar>(i);
		for (int j = 0; j<width; j++)
		{
    
    
			p1[j] = pixels[p2[j]];
		}
	}
	//归一化到0~255  
	normalize(imageLog, imageLog, 0, 255, NORM_MINMAX);
	//转换成8bit图像显示  
	convertScaleAbs(imageLog, imageLog);

	dstImage = imageLog.clone();

	return 0;

}

int ImgEnhance::GrayscaleTransform::ImageGammaTransform(cv::Mat srcImage, cv::Mat &dstImage, float c, float y)//伽马变换//s=c*r^y
{
    
    
	if (!srcImage.data || srcImage.channels() != 1)
	{
    
    
		return 1;
	}
	int height = srcImage.rows;
	int width = srcImage.cols;

	float pixels[256];
	for (int i = 0; i < 256; i++)
	{
    
    
		pixels[i] = c*powf(i, y);
	}

	Mat imageGamma(height, width, CV_32FC1);
	for (int i = 0; i<height; i++)
	{
    
    
		float* p1 = imageGamma.ptr<float>(i);
		uchar* p2 = srcImage.ptr<uchar>(i);
		for (int j = 0; j<width; j++)
		{
    
    
			p1[j] = pixels[p2[j]];
		}
	}
	//归一化到0~255  
	normalize(imageGamma, imageGamma, 0, 255, NORM_MINMAX);
	//转换成8bit图像显示  
	convertScaleAbs(imageGamma, imageGamma);

	dstImage = imageGamma.clone();

	return 0;

}

int ImgEnhance::GrayscaleTransform::ImageLinearTransform(cv::Mat srcImage, cv::Mat &dstImage, float a, float b)//线性变换//s=a*r+b
{
    
    

	if (!srcImage.data || srcImage.channels() != 1)
	{
    
    
		return 1;
	}
	int height = srcImage.rows;
	int width = srcImage.cols;

	float pixels[256];
	for (int i = 0; i < 256; i++)
	{
    
    
		pixels[i] = a*i+b;
	}

	Mat imageLinear(height, width, CV_32FC1);
	for (int i = 0; i<height; i++)
	{
    
    
		float* p1 = imageLinear.ptr<float>(i);
		uchar* p2 = srcImage.ptr<uchar>(i);
		for (int j = 0; j<width; j++)
		{
    
    
			p1[j] = pixels[p2[j]];
		}
	}
	//归一化到0~255  
	normalize(imageLinear, imageLinear, 0, 255, NORM_MINMAX);
	//转换成8bit图像显示  
	convertScaleAbs(imageLinear, imageLinear);

	dstImage = imageLinear.clone();

	return 0;
}

test.cpp

#include"grayTransform.h"

ImgEnhance::GrayscaleTransform ImgG;//灰度变换

int main()
{
    
    
	// 读取源图像及判断
	cv::Mat srcImage = cv::imread("flower.jpg");
	if (!srcImage.data)
	{
    
    
		return 1;
	}
	cv::namedWindow("原始图", 0);
	cv::imshow("原始图", srcImage);
	// 转化为灰度图像
	cv::Mat srcGray;
	if (srcImage.channels() == 3)
	{
    
    
		cv::cvtColor(srcImage, srcGray, COLOR_RGB2GRAY);
	}
	else
	{
    
    
		srcGray = srcImage.clone();
	}
	cv::namedWindow("灰度图", 0);
	cv::imshow("灰度图", srcGray);

	cv::Mat inverseMat;
	// 灰度反转 图像
	ImgG.ImageInverse(srcGray, inverseMat);
	cv::namedWindow("灰度反转图", 0);
	cv::imshow("灰度反转图", inverseMat);

	cv::Mat imageLogTransformMat;
	float cl = 10;
	// 对数变换 图像
	ImgG.ImageLogTransform(srcGray, imageLogTransformMat,cl);
	cv::namedWindow("对数变换图", 0);
	cv::imshow("对数变换图", imageLogTransformMat);

	cv::Mat imageGammaTransformMat;
	float cg = 1;
	float yg = 0.5;
	// 伽马变换 图像
	ImgG.ImageGammaTransform(srcGray, imageGammaTransformMat, cg,yg);
	cv::namedWindow("伽马变换图", 0);
	cv::imshow("伽马变换图", imageGammaTransformMat);

	cv::Mat imageLinearTransformMat;
	float a = 0.5;
	float b = 1;
	// 线性变换 图像
	ImgG.ImageGammaTransform(srcGray, imageLinearTransformMat, a, b);
	cv::namedWindow("线性变换图", 0);
	cv::imshow("线性变换图", imageLinearTransformMat);

	cv::waitKey(0);

	return 0;

}

结果图

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_40118285/article/details/126935458