opencv图像增强+单参数同态滤波

    图像处理中,对于图像增强有多种技术,主要分为空域增强技术以及频域增强技术。空域增强中,对于细节的强化有拉普拉斯锐化,对于整体图像的有直方图归一化,gamma变换,log变换等。而在频域增强中,以同态滤波为主。

    对于一幅图像,以轮廓为代表的细节主要集中在高频部分,因此,对于图像的增强,对于图像效果的强化主要是以增强高频为主。同态滤波就是这么一种滤波器,它的思想基于一副原图可以把它看做是入射分量以及反射分量的结合。即f(x,y)=i(x,y)*r(x,y),其中f(x,y)为原图像,i(x,y)为入射分量,r(x,y)为反射分量。入射分量因光照强度的一致性属于低频部分,光在经过物体表面反射时,即反射分量,反射分量可看做是物体自身的线性变换,属于高频部分,应该在图像处理中进行增强。那么我们目的就很明确了,找出一个频率滤波器,能够对高频进行增强,同时能够对低频进行相对抑制。传统的同态滤波有高斯同态滤波,巴特沃斯同态滤波器,指数型同态滤波器。式中,Rh、Rl分别为高频和低频增益,D0为截止频率,c是控制斜面锐化的常数,这三种同态滤波器都需要3种以上参数来进行控制,因此提出了一种改进型的同态滤波,仅需单个参数就能达到理想的效果,该传递函数为,该函数的三维图如下,传递函数的取值在[0,0.9],参数t是唯一一个控制参数


下面为同态滤波的主要流程


接着献上基于opencv的源码


#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int t = 1;
Mat src;


void homomorphic(int, void* userdata)
{
double t2 = (double)(t-10) / 110;
vector<Mat> rgb_split;
cv::split(src, rgb_split);
Mat dst;
for (int i = 0; i < 3; i++)
{
Mat original = rgb_split[i].clone();
Mat frame_log,padded,fourier_src,spatial,reinforce_src;
original.convertTo(frame_log, CV_32FC1);
frame_log += 1;
log(frame_log, frame_log);
//将图片从空域中转至频域
int m = frame_log.rows;
int n = frame_log.cols;
copyMakeBorder(frame_log, padded, 0, m - frame_log.rows, 0, n - frame_log.cols, BORDER_CONSTANT, Scalar::all(0));
Mat image_planes[] = { Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F) };
cv::merge(image_planes, 2, fourier_src);
dft(fourier_src, fourier_src);


//构造同态滤波器
Mat hu(fourier_src.size(), CV_32FC1, Scalar::all(0));
Point center = Point(hu.rows / 2, hu.cols / 2);
for (int i = 0; i < hu.rows; i++)
{
float* data = hu.ptr<float>(i);
for (int j = 0; j < hu.cols; j++)
data[j] = (double)1 / (1 + pow(sqrt(pow(center.x - i, 2) + pow((center.y - j), 2)), -t2));
}
Mat butterworth_channels[] = { Mat_<float>(hu), Mat::zeros(hu.size(), CV_32F) };
cv::merge(butterworth_channels, 2, hu);


//进行频域卷积操作,得到强化过后的频域图,将其转回空域
cv::mulSpectrums(fourier_src, hu, fourier_src, 0);
cv::idft(fourier_src, spatial, DFT_SCALE);

//对图像进行还原
cv::exp(spatial, spatial);
vector<Mat> planes;
cv::split(spatial, planes);
cv::magnitude(planes[0], planes[1], reinforce_src);
/*Mat temp;
normalize(reinforce_src, temp, 0, 255, NORM_MINMAX);
temp.convertTo(temp, CV_8UC1);*/
//这里采用偏差法对图像进行还原,类似的也可以用直方图归一化,只不过我试过直方图归一化效果不是很好
Mat mean_val, stddev_value;
cv::meanStdDev(reinforce_src, mean_val, stddev_value);
double min, max, minmax;
min = mean_val.at<double>(0, 0) - 2 * stddev_value.at<double>(0, 0);
max = mean_val.at<double>(0, 0) + 2 * stddev_value.at<double>(0, 0);
minmax = max - min;
for (int i = 0; i < planes[0].rows; i++)
for (int j = 0; j < planes[0].cols; j++)
reinforce_src.at<float>(i, j) = 255 * (reinforce_src.at<float>(i, j) - min) / minmax;
reinforce_src.convertTo(reinforce_src, CV_8UC1);
rgb_split[i] = reinforce_src.clone();

}
cv::merge(rgb_split, dst);
//下面对图像进行饱和度拉伸以及灰度线性变换以获得更加生动的图片
cvtColor(dst, dst, COLOR_BGR2HSV);
vector<Mat> hsv;
split(dst, hsv);
for (int i = 0; i < hsv[1].rows; i++)
for (int j = 0; j < hsv[1].cols; j++)
hsv[1].at<uchar>(i, j) = hsv[1].at<uchar>(i, j) * 4 / 3;
for (int i = 0; i < hsv[1].rows; i++)
for (int j = 0; j < hsv[1].cols; j++)
{
if (hsv[2].at<uchar>(i, j) < 235)
hsv[2].at<uchar>(i, j) = hsv[2].at<uchar>(i, j) * 45 /50-40;
/*else if (hsv[2].at<uchar>(i, j)>220)
hsv[2].at<uchar>(i, j) = (hsv[2].at<uchar>(i, j) - 151) * 55 / 180 + 200;*/
}
merge(hsv, dst);
cvtColor(dst, dst, COLOR_HSV2BGR);
imshow("效果图", dst);


}
Mat Fourier_Transform(Mat input)
{
Mat result;


return result;
}
int main(int argc, char** argv[])
{
src = imread("aaa.jpg");
imshow("原图", src);

createTrackbar("t", "原图", &t, 100, homomorphic);
waitKey(0);
return 0;
}

下面是原图


扫描二维码关注公众号,回复: 4249275 查看本文章

紧接的是效果图






        

猜你喜欢

转载自blog.csdn.net/qq_37333087/article/details/80485255