基于opencv的灰度变换

编程实验

72人已加入

描述

基于opencv的灰度变换

不同灰度变换只是使用的公式不同而已,核心思想都是在空间域直接对每一个像素的灰度值进行判断处理,代码很简单。

//基本灰度变换

#include

#include

#include

#include

#include

using namespace std;

using namespace cv;

#define CUTTING_MAINTAIN 1

#define CUTTING_LOW 0

OpenCV

//查看像素值

void View(Mat src)

{

ofstream PView;

PView.open("PView.txt");

int num = 0;

for (int i = 0;i < src.rows;i++)

{

for (int j = 0;j < src.cols;j++)

{

if (num == 50)

{

num = 0;

PView << endl;

}

else

{

int a = src.at(i, j);

PView << a << " ";

num++;

}

}

}

PView.close();

}

//图像反转

void Reverse(Mat src,Mat intermediate)

{

for (int i = 0;i < src.rows;i++)

{

for (int j = 0;j < src.cols;j++)

{

intermediate.at(i, j) = 255 - src.at(i, j);

}

}

}
#p##e#

//对数变换

void Log(Mat src, Mat intermediate,int c)

{

for (int i = 0;i < src.rows;i++)

{

for (int j = 0;j < src.cols;j++)

{

int b = c*log(1+src.at(i, j));

int d = b % 256;

intermediate.at(i, j) = d;

}

}

}

//幂次变换

void Power(Mat src, Mat intermediate,float gamma)

{

for (int i = 0;i < src.rows;i++)

{

for (int j = 0;j < src.cols;j++)

{

float c = pow(255, 1 - gamma);

int b = c*pow(src.at(i, j), gamma);

int d = b % 256;

intermediate.at(i, j) = d;

}

}

}

//对比拉伸

void Stretch(Mat src, Mat intermediate,float r1, float s1, float r2, float s2 )

{

float k1, k2, k3, b1, b2, b3;

k1 = s1 / r1;

b1 = 0.0;

k2 = (s2 - s1) / (r2 - r1);

b2 = (s1*r2 - s2*r1) / (r2 - r1);

k3 = (255.0 - s2) / (255.0 - r2);

b3 = (255.0*s2-r2*255.0) / (255.0 - r2);

cout << b3;

for (int i = 0;i < src.rows;i++)

{

for (int j = 0;j < src.cols;j++)

{

if (src.at(i, j) >= 0.0 && src.at(i, j) <= r1)

{

int a = k1*src.at(i, j) + b1;

int b = a % 256;

intermediate.at(i, j) = b;

}

if (src.at(i, j) >= r1 && src.at(i, j) <= r2)

{

int a = k2*src.at(i, j) + b2;

int b = a % 256;

intermediate.at(i, j) = b;

}

if (src.at(i, j) >= r2 && src.at(i, j) <= 255.0)

{

int a = k3*src.at(i, j) + b3;

int b = a % 256;

intermediate.at(i, j) = b;

}

}

}

}
#p##e#

//灰度切割

void Cutting(Mat src, Mat intermediate, float r1,float r2,int type,int low,int high)

{

if (type == CUTTING_MAINTAIN)

{

for (int i = 0;i < src.rows;i++)

{

for (int j = 0;j < src.cols;j++)

{

if (src.at(i, j) >= 0.0 && src.at(i, j) <= r1)

{

intermediate.at(i, j) = src.at(i, j);

}

if (src.at(i, j) >= r1 && src.at(i, j) <= r2)

{

intermediate.at(i, j) = high;

}

if (src.at(i, j) >= r2 && src.at(i, j) <= 255.0)

{

intermediate.at(i, j) = src.at(i, j);

}

}

}

}

else

{

for (int i = 0;i < src.rows;i++)

{

for (int j = 0;j < src.cols;j++)

{

if (src.at(i, j) >= 0.0 && src.at(i, j) <= r1)

{

intermediate.at(i, j) = low;

}

if (src.at(i, j) >= r1 && src.at(i, j) <= r2)

{

intermediate.at(i, j) = high;

}

if (src.at(i, j) >= r2 && src.at(i, j) <= 255.0)

{

intermediate.at(i, j) = low;

}

}

}

}

}

int main()

{

Mat src = cv::imread("Spectrum.tif", 0),temp;

Mat intermediate(src.rows, src.cols, CV_8UC1);

//cv::resize(src, temp, Size(src.cols*0.6, src.rows*0.6));

cv::imshow("Source", src);

//View(src);

Reverse(src, intermediate);

//Log(src, intermediate,45);

//Power(src, intermediate, 0.8);

//Stretch(src, intermediate,32.0,96.0,160.0,224.0);

//Cutting(src, intermediate, 50.0, 100.0,CUTTING_MAINTAIN,0,255);

//cv::resize(intermediate, intermediate, Size(intermediate.cols*0.6, intermediate.rows*0.6));

cv::imshow("intermediate", intermediate);

cv::imwrite("D:\\Computer Software\\Visual Studio 2015\\Projects\\ImageProcessing\\ImageProcessing\\检测结果Spectrum-Reverse.tif", intermediate);

cv::waitKey(0);

return 0;

}

代码里处理的图片都是《数字图像处理》的源图像,第二版的好像不再出版了,只找到了第三版的源图像,不过差不太多的。

附部分检测结果的图片:

1.幂次变换用于增强对比度:

源图像:

OpenCV

幂次变换(γ=0.4):
 

2.灰度切割:

源图像:

OpenCV

 

增强[50,100]区间灰度值为255,其余灰度值保持不变:

OpenCV

增强[50,100]区间灰度值为255,其余灰度值变化为0:

OpenCV

 

改进一下:

实现鼠标交互操作:使用鼠标圈出矩形框,只对矩形框内像素进行处理,可以更直观的观察某种算法对图像产生的变化。下面以对比拉伸为例:

#include

#include

#include

#include

using namespace std;

using namespace cv;

Rect rect;

bool rect_flag = false;

//获取鼠标所选取的矩形

void onMouse(int event,int x,int y,int flags,void*param)

{

if (event == CV_EVENT_LBUTTONDOWN)

{

rect.x = x;

rect.y = y;

rect_flag = false;

}

if (event == CV_EVENT_LBUTTONUP)

{

rect.width = x - rect.x;

rect.height = y - rect.y;

rect_flag = true;

}

}

//对比拉伸

void Stretch(Mat src, Mat intermediate,float r1, float s1, float r2, float s2 )

{

float k1, k2, k3, b1, b2, b3;

k1 = s1 / r1;

b1 = 0.0;

k2 = (s2 - s1) / (r2 - r1);

b2 = (s1*r2 - s2*r1) / (r2 - r1);

k3 = (255.0 - s2) / (255.0 - r2);

b3 = (255.0*s2-r2*255.0) / (255.0 - r2);

for (int i = rect.y;i < rect.y+rect.height;i++)

{

for (int j = rect.x;j < rect.x+rect.width;j++)

{

if (src.at(i, j) >= 0.0 && src.at(i, j) <= r1)

{

int a = k1*src.at(i, j) + b1;

int b = a % 256;

intermediate.at(i, j) = b;

}

if (src.at(i, j) >= r1 && src.at(i, j) <= r2)

{

int a = k2*src.at(i, j) + b2;

int b = a % 256;

intermediate.at(i, j) = b;

}

if (src.at(i, j) >= r2 && src.at(i, j) <= 255.0)

{

int a = k3*src.at(i, j) + b3;

int b = a % 256;

intermediate.at(i, j) = b;

}

}

}

}

int main()

{

Mat src = cv::imread("Pollen.tif", 0),temp, intermediate;

cv::resize(src, temp, Size(src.cols*0.6, src.rows*0.6));

cv::imshow("Source", temp);

namedWindow("intermediate",1);

setMouseCallback("intermediate", onMouse, 0);

while (1)

{

cv::resize(src, intermediate, Size(src.cols*0.6, src.rows*0.6));

//消除第一次画矩形后第二次点击鼠标直接在点击位置画出与上一个矩形等大矩形的情况

if (rect_flag)

{

Stretch(temp, intermediate, 100.0, 1.0, 120.0, 254.0);

cv::rectangle(intermediate, rect, Scalar(255, 0, 0), 1);

}

cv::imshow("intermediate", intermediate);

//ESC按键

char c = (char)waitKey(20);

if (27 == c)

return -1;

}

return 0;

}

效果图

OpenCV

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分