图像灰度线性变换
灰度线性变换是一种灰度变换,通过建立灰度映射来调整源图像的灰度,达到图像增强的目的。灰度映射通常使用灰度变换曲线来表示。
灰度线性变换就是将图像的像素值通过指定的线性函数进行变换,以此增强或减弱图像的灰度。灰度线性变换的公式是常见的一维线性函数:
g ( x , y ) = k ⋅ f ( x , y ) + b g(x,y) = k \cdot f(x,y) + b g(x,y)=k⋅f(x,y)+b
设 x x x为原始灰度值,则变换后的灰度值 y y y为:
y = k ⋅ x + b … … ( 0 ≤ y ≤ 255 ) y = k \cdot x + b \dots\dots(0 \leq y \leq 255) y=k⋅x+b……(0≤y≤255)
k k k表示直线的斜率,即倾斜程度, b b b表示线性函数在 y y y轴的截距。
k k k b b b取值 | 意义 |
---|---|
k > 1 k>1 k>1 | 增大图像的对比度,图像的像素值在变换后全部增大,整体效果被增强 |
k = 1 k=1 k=1 | 通过调整 b b b,实现对图像亮度的调整 |
0 < k < 1 0 < k < 1 0<k<1 | 图像的对比度被削弱 |
k < 0 k<0 k<0 | 原来图像亮的区域变暗,原来图像暗的区域变亮 |
clc;
clear;
close all;
% 对灰度图进行灰度线性变换
ori_img = imread('../images/6.jpg');
ori_img = rgb2gray(ori_img);
[oriHist,oriX] = imhist(ori_img);
k = 1.25;
d = 0;
gray1 = ori_img * k + d;
[g1Hist,g1X] = imhist(gray1);
k = 1;
d = 50;
gray2 = ori_img * k + d;
[g2Hist,g2X] = imhist(gray2);
k = 0.5;
d = 0;
gray3 = ori_img * k + d;
[g3Hist,g3X] = imhist(gray3);
k = -1;
d = 255;
ori_ = im2double(ori_img);
gray4 = ori_ * k + 1.0;
[g4Hist,g4X] = imhist(gray4);
figure(1),subplot(1,2,1),imshow(ori_img),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直方图');
figure(3),subplot(1,2,1),imshow(ori_img),title('原图');subplot(1,2,2),imshow(gray2),title('k=1 d=50');
figure(4),subplot(1,2,1),stem(oriX,oriHist),title('原图直方图');subplot(1,2,2),stem(g2X,g2Hist),title('k=1 d=50直方图');
figure(5),subplot(1,2,1),imshow(ori_img),title('原图');subplot(1,2,2),imshow(gray3),title('k=0.5 d=0');
figure(6),subplot(1,2,1),stem(oriX,oriHist),title('原图直方图');subplot(1,2,2),stem(g3X,g3Hist),title('k=0.5 d=0直方图');
figure(7),subplot(1,2,1),imshow(ori_img),title('原图');subplot(1,2,2),imshow(gray4),title('k=-1 d=255');
figure(8),subplot(1,2,1),stem(oriX,oriHist),title('原图直方图');subplot(1,2,2),stem(g4X,g4Hist),title('k=-1 d=255直方图');
#include
#include
#include "../include/opencv400/opencv2/opencv.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 <
线性变换是一个有限的查表操作,在C++实现时可以在将图像逐像素的计算过程转换为查表操作。由于灰度线性变换的查找表只需256字节,完全可以全部缓存到现代CPU的cache中,通过多线程的查表操作,可以加快整个图像的变换过程。当然,这样速度还是没有GPU中进行速度快。灰度线性变换是与相邻像素无关的操作,非常适合在GPU中并行计算。但需要根据图像大小,考虑图像从CPU到GPU再从GPU到CPU的时间损耗,时间加快只对很大的图有效。