【圖像處理】-002 圖像灰度線性變換

圖像灰度線性變換

1 概念

  灰度線性變換是一種灰度變換,通過建立灰度映射來調整源圖像的灰度,達到圖像增強的目的。灰度映射通常使用灰度變換曲線來表示。

2 原理

  灰度線性變換就是將圖像的像素值通過指定的線性函數進行變換,以此增強或減弱圖像的灰度。灰度線性變換的公式是常見的一維線性函數:
g(x,y)=kf(x,y)+b g(x,y) = k \cdot f(x,y) + b
xx爲原始灰度值,則變換後的灰度值yy爲:
y=kx+b(0y255) y = k \cdot x + b \dots\dots(0 \leq y \leq 255)
kk表示直線的斜率,即傾斜程度,bb表示線性函數在yy軸的截距。

3 作用

  

kk bb取值 意義
k>1k>1 增大圖像的對比度,圖像的像素值在變換後全部增大,整體效果被增強
k=1k=1 通過調整bb,實現對圖像亮度的調整
0<k<10 < k < 1 圖像的對比度被削弱
k<0k<0 原來圖像亮的區域變暗,原來圖像暗的區域變亮

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的時間損耗,時間加快只對很大的圖有效。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章