图像灰度线性变换
图像灰度线性变换
文章目录
1 概念
灰度线性变换是一种灰度变换,通过建立灰度映射来调整源图像的灰度,达到图像增强的目的。灰度映射通常使用灰度变换曲线来表示。
2 原理
灰度线性变换就是将图像的像素值通过指定的线性函数进行变换,以此增强或减弱图像的灰度。灰度线性变换的公式是常见的一维线性函数:
设为原始灰度值,则变换后的灰度值为:
表示直线的斜率,即倾斜程度,表示线性函数在轴的截距。
3 作用
取值 | 意义 |
---|---|
增大图像的对比度,图像的像素值在变换后全部增大,整体效果被增强 | |
通过调整,实现对图像亮度的调整 | |
图像的对比度被削弱 | |
原来图像亮的区域变暗,原来图像暗的区域变亮 |
4 Matlab实现
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直方图');
5 OpenCV实现
#include <iostream>
#include <string>
#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<float>(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);
//gray_img.convertTo(gray_img, CV_32FC1, 1.0 / 255);
cv::namedWindow("灰度图");
cv::imshow("灰度图", gray_img);
cv::Mat grayHist;
calcHist1D(gray_img, grayHist);
cv::imshow("hist", grayHist);
float k = 1.25;
int d = 0;
cv::Mat g1 = gray_img * k + d;
cv::Mat g1Hist;
calcHist1D(g1, g1Hist);
cv::imshow("g1", g1);
cv::imshow("g1Hist", g1Hist);
k = 1;
d = 30;
cv::Mat g2 = gray_img * k + d;
cv::Mat g2Hist;
calcHist1D(g2, g2Hist);
cv::imshow("g2", g2);
cv::imshow("g2Hist", g2Hist);
k = 0.5;
d = 0;
cv::Mat g3 = gray_img * k + d;
cv::Mat g3Hist;
calcHist1D(g3, g3Hist);
cv::imshow("g3", g3);
cv::imshow("g3Hist", g3Hist);
k = -1;
d = 255;
cv::Mat g4 = gray_img * k + d;
cv::Mat g4Hist;
calcHist1D(g4, g4Hist);
cv::imshow("g4", g4);
cv::imshow("g4Hist", g4Hist);
cv::waitKey();
return 0;
}
6 效果图
原图
6.1 效果图
k> 1 b=0
7 讨论
线性变换是一个有限的查表操作,在C++实现时可以在将图像逐像素的计算过程转换为查表操作。由于灰度线性变换的查找表只需256字节,完全可以全部缓存到现代CPU的cache中,通过多线程的查表操作,可以加快整个图像的变换过程。当然,这样速度还是没有GPU中进行速度快。灰度线性变换是与相邻像素无关的操作,非常适合在GPU中并行计算。但需要根据图像大小,考虑图像从CPU到GPU再从GPU到CPU的时间损耗,时间加快只对很大的图有效。