图像灰度非线性变换
图像灰度的非线性变换主要有对数变换、指数变换、幂次变换等。本文主要讨论对数变换。
对数变换的基本形式如下:
y = log ( 1 + x ) b y=\frac{\log{(1+x)}}{b} y=blog(1+x)
其中, b b b为正常数,用以控制曲线的弯曲程度。
对数变换实现了图像灰度扩展和压缩的功能,它扩展低灰度值而压缩高灰度值。
clc;
clear;
close all;
% 对灰度图进行灰度线性变换
ori_img = imread('../images/6.jpg');
ori_img1 = rgb2gray(ori_img);
[oriHist,oriX] = imhist(ori_img1);
ori_img = double(ori_img1);
k = 1.25;
d = 0;
gray1 = log(1+ori_img) /0.065;
gray1(find(gray1>255))=255;
gray1=uint8(gray1);
[g1Hist,g1X] = imhist(gray1);
figure(1),subplot(1,2,1),imshow(ori_img1),title('原图');subplot(1,2,2),imshow(gray1),title('k>0 d=0');
figure(2),subplot(1,2,1),stem(oriX,oriHist),title('原图直方图');subplot(1,2,2),stem(g1X,g1Hist),title('k>0 d=0直方图');
#include
#include
#include "../include/opencv400/opencv2/opencv.hpp"
#include "../include/opencv400/opencv2/core.hpp"
#include "windows.h"
std::string g_CurrentDirectory;
void SetCurrentDirectoryToExePath()
{
HMODULE hExe = GetModuleHandleA(NULL);
char nameBuf[MAX_PATH] = { 0 };
GetModuleFileNameA(hExe, nameBuf, MAX_PATH);
std::string sName(nameBuf);
sName = sName.substr(0, sName.rfind('\\'));
SetCurrentDirectoryA(sName.c_str());
g_CurrentDirectory = sName;
}
void calcHist1D(cv::Mat& input, cv::Mat& output)
{
int channels[] = { 0 };
int histsize[] = { 256 };
float grayRnage[] = { 0,256 };
const float* ranges[] = { grayRnage };
cv::MatND hist;
cv::calcHist(&input, 1, channels, cv::Mat(), hist, 1, histsize, ranges);
double maxVal = 0;
cv::minMaxLoc(hist, 0, &maxVal, 0, 0);
int scale = 10;
output = cv::Mat::zeros(500, 257 * 5, CV_8UC3);
//std::cout << "-----------------------------------" << std::endl;
for (int i = 0; i < histsize[0]; i++)
{
float binVal = hist.at(i, 0);
//std::cout << i << " " << binVal << std::endl;
int intensity = cvRound(binVal * 500 / maxVal);
rectangle(output, cv::Point(i * 5, 500 - intensity),
cv::Point((i + 1) * 5, 500),
cv::Scalar::all(255),
-1);
}
}
int main()
{
SetCurrentDirectoryToExePath();
cv::Mat ori_img = cv::imread("../images/6.jpg");
cv::Mat gray_img;
cv::cvtColor(ori_img, gray_img, cv::COLOR_BGR2GRAY);
cv::namedWindow("灰度图");
cv::imshow("灰度图", gray_img);
cv::Mat grayHist;
calcHist1D(gray_img, grayHist);
cv::imshow("hist", grayHist);
gray_img.convertTo(gray_img, CV_32FC1, 1.0 );
cv::Mat g1;
cv::log(1 + gray_img,g1);
g1 = g1 / 0.025;
cv::Mat m255(gray_img.rows, gray_img.cols, CV_32FC1);
m255 = cv::Scalar(255);
#undef min
cv::min(g1, m255, g1);
g1.convertTo(g1, CV_8UC1);
cv::Mat g1Hist;
calcHist1D(g1, g1Hist);
cv::imshow("g1Hist", g1Hist);
imshow("dd", g1);
cv::waitKey();
return 0;
}
OpenCV中提供了对cv::Mat
的log
,sqrt
,min
,max
等操作,在core.hpp
文件中。使用min
函数可以实现对Mat
中各元素超过阈值进行截断的功能。
例如,在上述实现中,对g1超过255的值进行截断,赋值为255.通过以下代码实现。
cv::Mat m255(gray_img.rows, gray_img.cols, CV_32FC1);
m255 = cv::Scalar(255);
#undef min
cv::min(g1, m255, g1);
注意其中的#undef min
,由于定义了宏min
,导致在调用cv::min
函数的时候会编译错误。