图像增强简介
分段线性法变换原理
代码实现和效果预览
疫情期间,楼主作为大三学生每天除了要应付网课和作业之外还得抽出时间准备研究生考试。虽说少了很多时间学习自己喜欢的知识,但近期由于课程作业关系需要在matlab上实现简单的图像处理的操作,楼主自然的想到先前曾接触过的Opencv功能强大便考虑能否自己实现其中的一些函数,经过一下午的折腾也算简单的实现了一个简单的部分。
苦中作乐,特写下此篇博客记录一下。
一、图像增强简介
图像增强即增强图像中的有用信息,其目的是要改善图像的视觉效果。可以分为两大类:频率域和空间域。
频率域的图像增强方法有低通滤波、高通滤波等等,而在空间域常采用点运算和邻域运算(也成为空间域滤波)。本文主要介绍点运算中的灰度变换方法。
灰度变换方法又分为:
1.反转变换
2.线性变换
3.分段线性变换
4.对数变换
5.幂律变换(伽马变换)
其中为了突出感兴趣的目标或灰度区间,相对抑制那些不感兴趣的灰度区域,常采用分段线性法。
二、分段线性法变换原则
为突出感兴趣的目标或灰度区间,相对抑制不感兴趣的灰度区域,可采用分段线性变换。
一般我们采用的是***三段线性变换法***,其数学表达式为:
三、代码实现和效果预览
void test1() {
/*获取RGB的像素值*/
Mat dst;
Mat src;
src = imread("D:\\VS2017\\Project\\Based_opencv_DIP\\classic.jpg", 1);
dst.create(src.size(), src.type());
int height = dst.rows;
int width = dst.cols;
int cn = src.channels();//通道数
int a = 256 * 0.3;
int b = 256 * 0.6;
int c = 256 * 0.1;
int d = 256 * 0.9;
int fa = (d - c) / (b - a);
int fb = (255 - d) / (255 - b);
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
if (cn == 1)
{
int gray = dst.at<uchar>(row, col);/*读取一个GRAY像素点的像素值(CV_8UC1)*/
dst.at<uchar>(row, col) = fa * (gray - a) + c;;//对每一个像素线性变换
}
else if (cn == 3)//分段线性变换
{
//这里的判断语句可自行更改
int blue = src.at<Vec3b>(row, col)[0];//第一个通道
int green = src.at<Vec3b>(row, col)[1];//第二个通道
int red = src.at<Vec3b>(row, col)[2];//第三个通道
if (blue< a) {
dst.at<Vec3b>(row, col)[0] = (c/a)*blue;
}
else if (blue > b) {
dst.at<Vec3b>(row, col)[0] = fb *(blue - b)+d;
}
else
dst.at<Vec3b>(row, col)[0] = fa * (blue - a) + c;
if (green < a) {
dst.at<Vec3b>(row, col)[1] = (c / a)*green;
}
else if (green > b) {
dst.at<Vec3b>(row, col)[1] = fb * (green - b) + d;
}
else
dst.at<Vec3b>(row, col)[1] = fa * (green - a) + c;
if (red < a) {
dst.at<Vec3b>(row, col)[2] = (c / a)*red;
}
else if (red > b) {
dst.at<Vec3b>(row, col)[2] = fb * (red - b) + d;
}
else
dst.at<Vec3b>(row, col)[2] = fa * (red - a) + c;
}
}
}
namedWindow("orignal image", WINDOW_AUTOSIZE);
namedWindow("trans image", WINDOW_AUTOSIZE);
imshow("orignal image", src);
imshow("trans image", dst);
imwrite("D:\\VS2017\\Project\\Based_opencv_DIP\\classic_trans.jpg", dst);
waitKey(0);
}
为了证实是否对图片进行了相对应的线性变换,进行一个小小的测试。将图片中的像素点读出写到txt文本中,对变换前后的图片像素进行比对来进行验证。其实现代码如下:
//将图片中的像素保存在txt当中
int main() {
GdiplusStartupInput gdiplusstartupinput;
ULONG_PTR gdiplustoken;
GdiplusStartup(&gdiplustoken, &gdiplusstartupinput, NULL);
wstring infilename(L"D:\\VS2017\\Project\\Based_opencv_DIP\\classic_trans.jpg");
string outfilename("color3.txt");
Bitmap* bmp = new Bitmap(infilename.c_str());
UINT height = bmp->GetHeight();
UINT width = bmp->GetWidth();
cout << "width " << width << ", height " << height << endl;
Color color;
ofstream fout(outfilename.c_str());
for (UINT y = 0; y < height; y++)
for (UINT x = 0; x < width; x++) {
bmp->GetPixel(x, y, &color);
fout << x << "," << y << ";"
<< (int)color.GetRed() << ","
<< (int)color.GetGreen() << ","
<< (int)color.GetBlue() << endl;
}
fout.close();
delete bmp;
GdiplusShutdown(gdiplustoken);
system("pause");
return 0;
}
通过对变换前后的两个图片的像素提取,对比两个txt文档我们即可验证所做变换的有效性。
四、总结
千里之行,始于足下。许久没用过opencv的我重新使用起初确实还是有一些费力,加上一下午的测试让人的眼睛也很是疲劳。好在最后得到了应有的效果,非常感谢网上各种前辈留下的可供参考的代码,给了我很多代码上的提示,不懂的地方还有太多,但坚持下去总会有积少成多水滴石穿的一天。
希望大家能够一起学习进步。