线性变换在图像处理
2012-08-17 23:58:45 lipeng08 阅读数 14163

灰度的线性变换

Db = f(Da) = k*Da +b   k为斜率,b为y轴交点截距,Da为输入图像的灰度,Db为输出图像的灰度

三个有趣的结论,相信会对灰度变换的理解更加深刻:

1,k> 1增加对比度,k<1减小对比度

2,k=1改变亮度

3,k=1,b=0保持原来图像,k=-1,b=255,原图像反转


以下讲述线性变换的代码的步骤:

1,判断参数是否是8位图像

2,对像素的所有点执行线性变换

3,对执行完像素变换的灰度值进行合法性分析,对不合法的数据强制合法

4,对图片的原来坐标的所有点设置新的灰度值。


以下代码转载自数字图像与机器视觉一书:

所有的代码我都亲自测试了,感觉不是很难,后面的可能会越来越难,先一点点啃吧。

BOOL CImgProcess::LinTranLP(CImgProcess* pTo, double dFa, double dFb)
{
if(m_pBMIH->biBitCount != 8) return false;


BYTE bGray,target;
for(int i = 0; i < m_pBMIH->biHeight; ++i)
{
for(int j = 0; j < m_pBMIH->biWidth; ++j)
{
bGray = GetGray(j,i);
target = dFa * bGray + dFb;
if(target < 0)
target = 0;
if(target > 255)
target = 255;
pTo->SetPixel(j, i, target);
}
}
return TRUE;
}

下面是采用的matlab的代码:

I = imread('coins.png'); % 读入原图像


I = im2double(I); % 转换数据类型为double
[M,N] = size(I); % 计算图像面积


figure(1); % 打开新窗口
imshow(I); % 显示原图像
title('原图像');


figure(2); % 打开新窗口
[H,x] = imhist(I, 64); % 计算64个小区间的灰度直方图
stem(x, (H/M/N), '.'); % 显示原图像的直方图
title('原图像');


% 增加对比度
Fa = 2; Fb = -55;
O = Fa * I + Fb/255;


figure(3);
subplot(2,2,1);
imshow(O);
title('Fa = 2 Fb = -55 增加对比度');


figure(4);
subplot(2,2,1);
[H,x] = imhist(O, 64);
stem(x, (H/M/N), '.');
title('Fa = 2 Fb = -55 增加对比度');


% 减小对比度
Fa = 0.5; Fb = -55;
O = Fa * I + Fb/255;


figure(3);
subplot(2,2,2);
imshow(O);
title('Fa = 0.5 Fb = -55 减小对比度');


figure(4);
subplot(2,2,2);
[H,x] = imhist(O, 64);
stem(x, (H/M/N), '.');
title('Fa = 0.5 Fb = -55 减小对比度');


% 线性增加亮度
Fa = 1; Fb = 55;
O = Fa * I + Fb/255;


figure(3);
subplot(2,2,3);
imshow(O);
title('Fa = 1 Fb = 55 线性平移增加亮度');


figure(4);
subplot(2,2,3);
[H,x] = imhist(O, 64);
stem(x, (H/M/N), '.');
title('Fa = 1 Fb = 55 线性平移增加亮度');


% 反相显示
Fa = -1; Fb = 255;
O = Fa * I + Fb/255;


figure(3);
subplot(2,2,4);
imshow(O);
title('Fa = -1 Fb = 255 反相显示');


figure(4);
subplot(2,2,4);
[H,x] = imhist(O, 64);
stem(x, (H/M/N), '.');
title('Fa = -1 Fb = 255 反相显示');

2012-03-29 22:22:01 Lnstree 阅读数 1502

上篇讲了直方图均衡化。

这篇讲的是灰度的线性变换。  这些都是比较基础的处理方法。

最近在看傅立叶变换,感慨自己那时候高数,线性代数没学会。

许多人,都觉得大学的许多科目跟实际生活没什么挂钩,我个人也这么觉得。

但相比大学空闲的时间,即便不学,也要了解下。  不然,假如某天你要用到一些东西,或许你都不知道从哪入手。

好了进入正题:

灰度线性变换:

灰度的线性变换就是将图像中所有的点按照线性灰度变换函数进行变换。该线性灰度变换函数f(x)是一个一维线性函数:
              f(x)=fA*x+fB
灰度变换方程为:
              D2=f(D1)=fA*D+fB
式中参数fA为线性函数的斜率,fB为线性函数的在y轴上的截距,D1为输入图像的灰度,D2为输出的图像灰度。当fA>1时,输出的图像的对比度增大;当fA<1时,输出图像的对比度将减小;当fA=1且fB!=0时,操作仅仅使所有像素的灰度值上移或下移,其效果是使整个图像更亮或更暗;特殊情况下,如果fA=1,fB=0时,输出图像和输入图像相同;当fA=-1,fB=255时,输出图像的灰度正好反转。
 
以上是百度知道上的解释,解释基本没问题。
 
源码:
 
 public static Bitmap GayLinesChange(Bitmap tp, double a, double b)
       {
           int w = tp.Width;
           int h = tp.Height;
           int i, j, gray;
           byte [] ky = new byte[w*h];
           ky = ChangeByte(tp);
            for (i = 0; i < h; i++)
            {
                for (j = 0; j < w; j++)
                {
                    gray = (int)(ky[i * w + j] * a + b);
                    if (gray > 255)
                        gray = 255;
                    else if (gray < 0)
                        gray = 0;
                    ky[i * w + j] = (byte)(gray);
                }
            }           tp = ChangeBitmap(ky, tp);
           return tp;
       }
关于 ChangeBitmap() 以及 ChangeByte(); 前面已经提到。
OK了。
2018-12-09 19:41:37 freehawkzk 阅读数 359

图像灰度线性变换

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&gt;1k&gt;1 增大图像的对比度,图像的像素值在变换后全部增大,整体效果被增强
k=1k=1 通过调整bb,实现对图像亮度的调整
0&lt;k&lt;10 &lt; k &lt; 1 图像的对比度被削弱
k&lt;0k&lt;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的时间损耗,时间加快只对很大的图有效。

2012-06-13 12:43:30 fuyun_613 阅读数 3807
线性变换是灰度变换的一种,图像的灰度变换通过建立灰度映射来调整源图像的灰度从而达到图像增强的目的。

     其公式可以表示为y(x, y) = k * x(x, y) + b;其中y(x, y)表示目标像素值,x(x, y)表示源像素值,k表示斜率,b表示截距。 

    1)当k>1时,可用于增加图像的对比度。图像的像素值在变换后全部增大,整体显示效果被增强。

    2)当k=1时,常用于调节图像亮度。

    3)当0<k<1时,效果与k>1时刚刚相反,图像的对比度和整体效果都被削弱。

    4)当k<0时,源图像较亮的区域变暗,而较暗的区域会变亮。此时可以使函数中的k=-1,d=255让图像实现反色效果。

     代码如下:

  1. /******************************************************************************    
  2. *   作用:     线性变换函数
  3. *   参数: pDst     输出图像的像素数组
  4. *   参数: pSrc     原始图像的像素数组
  5. *   参数: nWidth   原始图像宽度
  6. *   参数: nHeight  原始图像高度
  7. *   参数: slope      线性函数的斜率
  8. *   参数: inter      线性函数的截距
  9. *   备注: 此函数对于彩色图同样适用
  10. ******************************************************************************/ 
  11. int LineTrans(BYTE* pDst, BYTE* pSrc, int nWidth, int nHeight, double slope, double inter) 
  12.     if (!pSrc || !pDst) 
  13.     { 
  14.         return EXIT_FAILURE; 
  15.     } 
  16.  
  17.     // 灰度映射表 
  18.     BYTE map[256]; 
  19.  
  20.     // 保存运算后的临时值 
  21.     double dTemp; 
  22.     int i, j; 
  23.     for (i = 0; i < 256; i++) 
  24.     { 
  25.         // 计算当前像素变换后的值 
  26.         dTemp = slope * i + inter; 
  27.  
  28.         // 如果超界则修改其值 
  29.         if (dTemp < 0) 
  30.             dTemp = 0.0; 
  31.         else if (dTemp > 255) 
  32.             dTemp = 255; 
  33.  
  34.         // 四舍五入 
  35.         map[i] = int(dTemp + 0.5); 
  36.     } 
  37.  
  38.     // 线性变换后的值直接在映射表中查找 
  39.     for (i = 0; i < nWidth * nHeight; i++) 
  40.     {    
  41.         for (j = 0; j < 4; j++) 
  42.             pDst[i*4 + j] = map[pSrc[i*4 + j]]; 
  43.     } 
  44.     return EXIT_SUCCESS; 

  

2010-05-23 14:28:00 yangfenghero 阅读数 1914

    线性变换是灰度变换的一种,图像的灰度变换通过建立灰度映射来调整源图像的灰度从而达到图像增强的目的。

     其公式可以表示为y(x, y) = k * x(x, y) + b;其中y(x, y)表示目标像素值,x(x, y)表示源像素值,k表示斜率,b表示截距。 

    1)当k>1时,可用于增加图像的对比度。图像的像素值在变换后全部增大,整体显示效果被增强。

    2)当k=1时,常用于调节图像亮度。

    3)当0<k<1时,效果与k>1时刚刚相反,图像的对比度和整体效果都被削弱。

    4)当k<0时,源图像较亮的区域变暗,而较暗的区域会变亮。此时可以使函数中的k=-1,d=255让图像实现反色效果。

     代码如下:

   

 

 

    

没有更多推荐了,返回首页