基于opencv的c++接口,实现常用的图像灰度变换方法,包括了线性变换、图像反转、对数变换和伽马变换。
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=cr^y,其中,r表示原始图像的灰度级,s表示变换后的灰度级,c为比例系数,y为幂数。
线性变换公式:s=a*r+b,其中,r表示原始图像的灰度级,s表示变换后的灰度级,a为比例系数,b为平移系数。
#pragma once
#include
#include
#include
#include
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
};
}
#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;
}
#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;
}