1.公式
1.1线性变换
假设原图像 f(x,y)的灰度范围为[a,b],希望变换后图像 g(x,y)的灰度范围扩展至[c,d],则灰度线性变换可表示为
1.2分段线性变换
2.C++代码实现
#include "cv.h"
#include "highgui.h"
#include "cvaux.h"
#include "cxcore.h"
#include "opencv2/opencv.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
#include <string>
using namespace cv;
using namespace std;
Mat image;//原图像
Mat target1;//输出图像
Mat target2;
//原始图像灰度范围[a,b]
int a = 255;
int b = 0;
//灰度线性变换,前提是传入的图像是灰度图
void toGray(Mat src, float c, float d)
{
target1 = Mat::zeros(src.size(), src.type());
for (int i = 0; i < src.rows; i++)
{
for (int j = 0; j < src.cols; j++)
{
//线性变换,saturate_cast作用是防止数组越界
target1.at<uchar>(i, j) = saturate_cast<uchar>(( d-c)/(b-a) * (src.at<uchar>(i, j) -a ) + c);
}
}
}
//灰度分段线性变换(这里有个小疑惑,可能写错了,我没有按照公式来写)
void piecewiseToGray(Mat src, float c, int d)
{
target2 = Mat::zeros(src.size(), src.type());
for (int i = 0; i < src.rows; i++)
{
for (int j = 0; j < src.cols; j++)
{
if(target2.at<uchar>(i, j) < c)
target2.at<uchar>(i, j) = saturate_cast<uchar>( (c/a) * src.at<uchar>(i, j) );
else if(c < target2.at<uchar>(i, j) && target2.at<uchar>(i, j) < d )
target2.at<uchar>(i, j) = saturate_cast<uchar>((d - c) / (b - a) * (src.at<uchar>(i, j) - a) + c);
else
target2.at<uchar>(i, j) = saturate_cast<uchar>((255-d) / (255-b) * (src.at<uchar>(i, j) - b) + d);
}
}
}
//获取原图像灰度范围
void getGrayValue(Mat src)
{
int value = 0;
for (int i = 0; i < src.rows; i++)
{
for (int j = 0; j < src.cols; j++)
{
value = (int)src.at<uchar>(i, j);
if (value > b)
b = value;
if (value < a)
a = value;
}
}
}
int main()
{
//加上0表示读入灰度图
image = imread("D:/opencv/testPic/d1.bmp",0);
if (image.empty())
{
printf("could not load pic!\n");
return -1;
}
namedWindow("src");
imshow("src", image);
//获得原图像灰度范围
getGrayValue(image);
//输入目标图像灰度范围
int c = 50;
int d = 150;
//根据目标图像灰度范围生成目标图像
toGray(image, c, d);
piecewiseToGray(image, c, d);
//Mat target = 255 - src; //相当于a=-1,b=255,OpenCV中有对Mat的运算符重载,可以直接Mat r = 255 - img或者~img来实现
namedWindow("target1", WINDOW_AUTOSIZE);
namedWindow("target2", WINDOW_AUTOSIZE);
imshow("target1", target1);
imshow("target2", target2);
imwrite("D:/opencv/testPic/d2.bmp",target1);
imwrite("D:/opencv/testPic/d3.bmp", target2);
waitKey(0);
return 0;
}