图像处理 线性变换

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

     其公式可以表示为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; 

  

2015-12-11 08:14:57 liu_xiao_cheng 阅读数 3469

1.灰度线性变换:F(x)=a*f(x)+b

int IMGChange(IplImage *src,IplImage *dest, float slope,float intercept)
{
 if(NULL == src)
  return -1;

 if(src->nChannels!=1 || dest->nChannels!=1)
 {
  cout<<"It's not gray image!"<<endl;
  return -1;
 }
 float gray = 0; 
 for(int i = 0;i < src->height;i++){ 
  for(int j = 0; j < src->width; j++){ 
 
   gray = (float)src->imageData[src->widthStep * i + j ];
   gray = slope*gray + intercept;
   dest->imageData[dest->widthStep * i + j ]=gray;
        } 
    } 
 return 0;
}

当slope=-1   intercept=255即为图像反转


2.伽马变换,s=c*(r)γ,可用于图像增强等预处理。

int IMGgammaChange(IplImage *src,IplImage *dest, double gamma,double comp)
{
 if(NULL == src)
  return -1;

 if(src->nChannels!=1 || dest->nChannels!=1)
 {
  cout<<"It's not gray image!"<<endl;
  return -1;
 }
 double gray = 0; 
 for(int i = 0;i < src->height;i++){ 
  for(int j = 0; j < src->width; j++){ 
 
   gray = (double)src->imageData[src->widthStep * i + j ];
   gray =pow((gray+comp)/255.0,gamma)*255;
   dest->imageData[dest->widthStep * i + j ]=gray;
        } 
    } 
 return 0;
}




2016-06-13 14:05:59 wenhao_ir 阅读数 1582

图像的线性变换是图像处理的基本运算,通常应用在调整图像的画面质量方面,如图像对比度、亮度及反转等操作。对于输入图像f(x,y),输出图像g(x,y),其线性变换表达式为:

其中参数a表示图像对比度变化,b表示图像亮度变化。当a<0时,图像变换代表反转操作,如a=-1、b=255,这是常见的8位灰度图像的反转操作设置参数;当|a|>1时,图像变换代表对比度增加操作;当|a|<1时,图像变换代表对比度减少操作。当b>0时,表示图像变换操作是亮度增加操作;b<0时,表示图像变换操作是亮度减少操作。

线性变换的OpenCV源代码如下图所示:

源码中用到的图像的下载链接为:http://pan.baidu.com/s/1i4Dvm2h

图像处理开发资料、图像处理开发需求、图像处理接私活挣零花钱,可以搜索公众号"qxsf321",并关注!

 

//OpenCV版本2.4.9  
//图像处理开发资料、图像处理开发需求、图像处理接私活挣零花钱,可以搜索公众号"qxsf321",并关注!

#include <opencv2/core/core.hpp>        
#include <opencv2/highgui/highgui.hpp> 
#include <opencv2/imgproc/imgproc.hpp>  
#include <iostream> 
using namespace cv;
// 图像线性变换操作
cv::Mat linearTransform(cv::Mat srcImage, float a, int b)
{
    if(srcImage.empty()){  
        std::cout<< "No data!" <<std::endl;  
    } 
    const int nRows = srcImage.rows;
    const int nCols = srcImage.cols;
    cv::Mat resultImage = 
        cv::Mat::zeros(srcImage.size(), srcImage.type());
    // 图像元素遍历
    for( int i = 0; i < nRows; i++ )
    {
        for( int j = 0; j < nCols; j++ )
        {
            for( int c = 0; c < 3; c++ )//如果源图像是灰度图,那么把这里改为c<1即可
            {
                // 矩阵at操作,检查下标防止越界
                resultImage.at<Vec3b>(i,j)[c] = 
                  saturate_cast<uchar>(a * 
                  (srcImage.at<Vec3b>(i,j)[c]) + b);
            }
        }
    }
    return resultImage;
}
int main()
{
    // 图像获取及验证
    cv::Mat srcImage = cv::imread("lakeWater.jpg"); 
    if(!srcImage.data) 
       return -1;
    cv::imshow("srcImage", srcImage);
    //cv::waitKey(0);
    // 线性变换
    float a = 1.2;
    int b = 50;
    cv::Mat new_image  = linearTransform(srcImage, a, b);  
    cv::imshow("dst", new_image);
    cv::waitKey(0);
    return 0;
}

 

运行结果如下图所示:

 

2018-12-09 19:41:37 freehawkzk 阅读数 1932

图像灰度线性变换

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的时间损耗,时间加快只对很大的图有效。

2014-12-10 22:57:57 whustyle 阅读数 1689


    承接上一篇博客,接下来实现以下灰度图像的线性拉伸变换,具体理论就不赘述了,学过数字图像处理的基本都知道,下面来看看如何通过VC6.0的MFC编程实现它。

首先打开工作空间的resources视窗,创建菜单项,如下:



然后为菜单创建消息响应函数,右键灰度线性变换,选择ClassWizard,创建单击事件函数:




确定,点击EditCode后发现有View.cpp中已经有如下代码:


void CImageProcessView::OnLinertrans() 
{
	// TODO: Add your command handler code here
	
}

    下面,我们需要创建一个对话框,来接受用户设置的线性变换参数,最小值和最大值,可以右键Dialog,InsertDialog,设置对话框ID为:IDD_DIALOG_LinerTransSet

添加两个Edit编辑框,ID分别为:IDC_EDIT_MAX、IDC_EDIT_MIN,如下:



    为对话框创建类,双击对话框,提示创建新的类,选择确定,设置类参数如下:



确定之后,为两个Edit对象创建成员变量,在上面的类向导中,选择Member Variables选项卡,创建成员变量如下:



        这些准备工作做好了之后,便可以实现前面空着的OnLinertrans函数了,先在View.cpp文件上方添加头文件包含# include "LinerTransDlg.h",然后实现OnLinertrans,

直接上代码如下:

void CImageProcessView::OnLinertrans() 
{
	// TODO: Add your command handler code here
	CLinerTransDlg linedlg;
	
	if(linedlg.DoModal()==IDOK)
	{
		UpdateData(TRUE);
		CImageProcessDoc* pDoc=GetDocument();
		ASSERT_VALID(pDoc);
		
		BYTE* pData=pDoc->m_bmpFile.m_pImgDat;
		
		int cols=pDoc->m_bmpFile.m_Cols;
		int rows=pDoc->m_bmpFile.m_Rows;
		int min=linedlg.m_nMin;
		int max=linedlg.m_nMax;
		
		float mingray=255,maxgray=0;
		
		for(int r=0;r<rows;r++)
		{
			for(int c=0;c<cols;c++)
			{
				if(*(pData+cols*r+c)<mingray)
					mingray=*(pData+cols*r+c);
				
				if(*(pData+cols*r+c)>maxgray)
					maxgray=*(pData+cols*r+c);
				
			}
		}
		float a=(min-max)/(mingray-maxgray);
		for(r=0;r<rows;r++)
		{
			for(int c=0;c<cols;c++)
			{
				int gray=int(min+a*(*(pData+cols*r+c)-mingray));
				*(pData+cols*r+c)=BYTE(gray);
			}
		}
		Invalidate();
	}
}

这样,整个编程任务完成,运行程序:



确定后结果如下:



写博客不多,欢迎指正微笑,附上源码下载地址:http://download.csdn.net/detail/whustyle/8246103