2018-10-06 17:29:45 huangxin388 阅读数 626

        这是一种输出灰度级与输入灰度级呈非线性关系的点运算。前面讲过的“非0即1法”,固定阈值法,双固定阈值法等都属于非线性变换。这里再补充几种常用的非线性变换。

一、灰度对数变换

        对数变换实现了图像的灰度扩展和压缩的功能。它扩展低灰度值而压缩高灰度值,让图像的分布更加符合人的视觉特征。

 

灰度对数变换公式如下(图像就不画了,不同的a和b产生不同的对数图像,对图像的扩展和压缩也相应改变)

 

                                                    y = a+log(1+x)/b

下面的例子中我们取a = 10,b = 0.025

思路:

  1. 传入需要处理的图像    
  2. 遍历整个图像取出图像中每个点的像素值存到一个数组中(oldPix)
  3. 在循环中获取每个像素点的颜色值,并抽取每个像素中的r,g,b,a分量准备处理
  4. 利用灰度公式计算出每个点的灰度值(范围0-255),并做溢出处理
  5. 令某点的灰度值gray = log(gray+1)/0.025+10
  6. 如果某点的灰度值小于阈值下限则将其灰度值置为0
  7. 如果某点的灰度值大于阈值上限则将其灰度值置为255
  8. 将处理后的灰度值合成像素点的颜色值,存到一个新数组中(newPix)
  9. 创建一个高度、宽度和原图完全一样的新图
  10. 将新图像返回
   private Bitmap logarithm(Bitmap bm) {
        int width = bm.getWidth();//原图像宽度
        int height = bm.getHeight();//原图高度
        int color;//用来存储某个像素点的颜色值
        int gray;//用来存储计算得到的灰度值
        int r, g, b, a;//红,绿,蓝,透明度
        //创建空白图像,宽度等于原图宽度,高度等于原图高度,用ARGB_8888渲染,这个不用了解,这样写就行了
        Bitmap bmp = Bitmap.createBitmap(width, height
                , Bitmap.Config.ARGB_8888);

        int[] oldPx = new int[width * height];//用来存储原图每个像素点的颜色信息
        int[] newPx = new int[width * height];//用来处理处理之后的每个像素点的颜色信息
        /**
         * 第一个参数oldPix[]:用来接收(存储)bm这个图像中像素点颜色信息的数组//The array to receive the bitmap’s colors
         * 第二个参数offset:oldPix[]数组中第一个接收颜色信息的下标值// The first index to write into pixels[]
         * 第三个参数width:在行之间跳过像素的条目数,必须大于等于图像每行的像素数//The number of entries in pixels[] to skip between rows (must be >= bitmap’s width). Can be negative.
         * 第四个参数x:从图像bm中读取的第一个像素的横坐标 The x coordinate of the first pixel to read from the bitmap
         * 第五个参数y:从图像bm中读取的第一个像素的纵坐标The y coordinate of the first pixel to read from the bitmap
         * 第六个参数width:每行需要读取的像素个数The number of pixels to read from each row
         * 第七个参数height:需要读取的行总数The number of rows to read
         */
        bm.getPixels(oldPx, 0, width, 0, 0, width, height);

        for (int i = 0; i < width * height; i++) {//循环处理图像中每个像素点的颜色值
            color = oldPx[i];//取得某个点的像素值
            r = Color.red(color);//取得此像素点的r(红色)分量
            g = Color.green(color);//取得此像素点的g(绿色)分量
            b = Color.blue(color);//取得此像素点的b(蓝色分量)
            a = Color.alpha(color);//取得此像素点的a通道值
            //此公式将r,g,b运算获得灰度值,经验公式不需要理解
            gray = (int)((float)r*0.3+(float)g*0.59+(float)b*0.11);

            gray = (int)(Math.log((float)gray + 1.0f)/0.025f + 10.0f);
            //溢出处理
            if(gray < 0) {
                gray = 0;
            } else if(gray > 255) {
                gray = 255;
            }

            newPx[i] = Color.argb(a,gray,gray,gray);
        }
        bmp.setPixels(newPx, 0, width, 0, 0, width, height);//将处理后的透明度(没变),r,g,b分量重新合成颜色值并将其存储在数组中
        return bmp;//返回处理后的图像
    }

效果

二、灰度指数变换

        指数变换的作用是扩展图像的高灰度级,压缩低灰度级。虽然幂次变换也有这个功能,但是图像经过指数变换后对比度更高,高灰度级也扩展到了更宽的范围。 

 

灰度指数变换的基本公式如下

下面的例子中我们取b = 1.5,c = 0.065,a = 0

思路:

  1. 传入需要处理的图像    
  2. 遍历整个图像取出图像中每个点的像素值存到一个数组中(oldPix)
  3. 在循环中获取每个像素点的颜色值,并抽取每个像素中的r,g,b,a分量准备处理
  4. 利用灰度公式计算出每个点的灰度值(范围0-255),并做溢出处理
  5. 令某点的灰度值gray = 1.5^{0.065*(gray-0)}-1
  6. 如果某点的灰度值小于阈值下限则将其灰度值置为0
  7. 如果某点的灰度值大于阈值上限则将其灰度值置为255
  8. 将处理后的灰度值合成像素点的颜色值,存到一个新数组中(newPix)
  9. 创建一个高度、宽度和原图完全一样的新图
  10. 将新图像返回
   private void exponetial(Bitmap bm) {
        int width = bm.getWidth();//原图像宽度
        int height = bm.getHeight();//原图高度
        int color;
        int r, g, b, a;

        Bitmap bmp = Bitmap.createBitmap(width, height
                , Bitmap.Config.ARGB_8888);

        int[] oldPx = new int[width * height];
        int[] newPx = new int[width * height];
        bm.getPixels(oldPx, 0, width, 0, 0, width, height);

        for (int i = 0; i < width * height; i++) {
            color = oldPx[i];
            r = Color.red(color);
            g = Color.green(color);
            b = Color.blue(color);
            a = Color.alpha(color);

            int gray = (int)((float)r*0.3+(float)g*0.59+(float)b*0.11);
            gray = (int)(Math.pow(1.5f,0.065f * (gray - 0)) - 1.0f);
            if(gray < 0) {
                gray = 0;
            } else if(gray > 255) {
                gray = 255;
            }

            newPx[i] = Color.argb(a,gray,gray,gray);
        }
        bmp.setPixels(newPx, 0, width, 0, 0, width, height);
        mImageView.setImageBitmap(bmp);
    }

效果

 

 

 

 

 

 

 

 

 

 

三、灰度幂次变换

        幂次变换将部分灰度区域映射到更宽的区域中。

 

灰度幂次变换的基本公式如下(取r = 1时变为线性变换)

由于直接进行幂次变换会使大部分像素的灰度值超过255,因此我们先将某点的灰度值除以255,进行灰度变换后再将结果乘以255。

思路

  1. 传入需要处理的图像    
  2. 遍历整个图像取出图像中每个点的像素值存到一个数组中(oldPix)
  3. 在循环中获取每个像素点的颜色值,并抽取每个像素中的r,g,b,a分量准备处理
  4. 利用灰度公式计算出每个点的灰度值(范围0-255),并做溢出处理
  5. 令某点的灰度值gray = (gray/255)^{1.7}*255+20
  6. 如果某点的灰度值小于阈值下限则将其灰度值置为0
  7. 如果某点的灰度值大于阈值上限则将其灰度值置为255
  8. 将处理后的灰度值合成像素点的颜色值,存到一个新数组中(newPix)
  9. 创建一个高度、宽度和原图完全一样的新图
  10. 将新图像返回
    private void power(Bitmap bm) {
        int width = bm.getWidth();
        int height = bm.getHeight();
        int color;
        int r, g, b, a;

        Bitmap bmp = Bitmap.createBitmap(width, height
                , Bitmap.Config.ARGB_8888);

        int[] oldPx = new int[width * height];
        int[] newPx = new int[width * height];
        bm.getPixels(oldPx, 0, width, 0, 0, width, height);

        for (int i = 0; i < width * height; i++) {
            color = oldPx[i];
            r = Color.red(color);
            g = Color.green(color);
            b = Color.blue(color);
            a = Color.alpha(color);

            int gray = (int)((float)r*0.3+(float)g*0.59+(float)b*0.11);
            gray = (int)(1.0f * Math.pow(gray/255.0f,1.7f) * 255 + 20);
            if(gray < 0) {
                gray = 0;
            } else if(gray > 255) {
                gray = 255;
            }

            newPx[i] = Color.argb(a,gray,gray,gray);
        }
        bmp.setPixels(newPx, 0, width, 0, 0, width, height);
        mImageView.setImageBitmap(bmp);
    }

效果

 

 代码已上传到github,点击这里可以下载体验

2018-12-09 22:53:39 freehawkzk 阅读数 1475

图像灰度非线性变换

1 原理

  图像灰度的非线性变换主要有对数变换、指数变换、幂次变换等。本文主要讨论对数变换。

  对数变换的基本形式如下:
y=log(1+x)b y=\frac{\log{(1+x)}}{b}
其中,bb为正常数,用以控制曲线的弯曲程度。

  对数变换实现了图像灰度扩展和压缩的功能,它扩展低灰度值而压缩高灰度值。

2 Matlab实现

clc;
clear;
close all;

% 对灰度图进行灰度线性变换
ori_img = imread('../images/6.jpg');
ori_img1 = rgb2gray(ori_img);
[oriHist,oriX] = imhist(ori_img1);
ori_img = double(ori_img1);

k = 1.25;
d = 0;
gray1 = log(1+ori_img) /0.065;
gray1(find(gray1>255))=255;
gray1=uint8(gray1);
[g1Hist,g1X] = imhist(gray1);


figure(1),subplot(1,2,1),imshow(ori_img1),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直方图');

3 OpenCV实现

3.1 实现

#include <iostream>
#include <string>

#include "../include/opencv400/opencv2/opencv.hpp"
#include "../include/opencv400/opencv2/core.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);
	cv::namedWindow("灰度图");
	cv::imshow("灰度图", gray_img);

	cv::Mat grayHist;
	calcHist1D(gray_img, grayHist);
	cv::imshow("hist", grayHist);

	gray_img.convertTo(gray_img, CV_32FC1, 1.0 );

	cv::Mat g1;
	cv::log(1 + gray_img,g1);
	g1 = g1 / 0.025;

	cv::Mat m255(gray_img.rows, gray_img.cols, CV_32FC1);
	m255 = cv::Scalar(255);
#undef min
	cv::min(g1, m255, g1);
	g1.convertTo(g1, CV_8UC1);
	cv::Mat g1Hist;
	calcHist1D(g1, g1Hist);
	cv::imshow("g1Hist", g1Hist);
	imshow("dd", g1);

	

	cv::waitKey();
	return 0;
}

3.2 注意

  OpenCV中提供了对cv::Matlog,sqrt,min,max等操作,在core.hpp文件中。使用min函数可以实现对Mat中各元素超过阈值进行截断的功能。
例如,在上述实现中,对g1超过255的值进行截断,赋值为255.通过以下代码实现。

	cv::Mat m255(gray_img.rows, gray_img.cols, CV_32FC1);
	m255 = cv::Scalar(255);
#undef min
	cv::min(g1, m255, g1);

注意其中的#undef min,由于定义了宏min,导致在调用cv::min函数的时候会编译错误。

4 效果图

在这里插入图片描述在这里插入图片描述

2019-12-23 13:00:25 weixin_44244154 阅读数 27

实验内容

一、自选一幅背景较复杂、前景目标较多的交通图像,编程实现如下内容,并写出实验报告。
1、分段线性变换各种情况的变换效果对比
2、对数、指数变换、取反等各种非线性变换的效果对比,务必有仿真结果及其详细的对比分析
二、1、已知某灰度图像数据如下,请对其进行直方图均衡化
在这里插入图片描述
2、已知某灰度图像数据如下,请用Gml和SML两种映射规则对其进行直方图规定化,对比变换后的直方图。
在这里插入图片描述

1.1线性变换代码:

由于给出的图像是3维RGB彩色图像,故在读取图像后可分为三个方向分别对图像进行操作,即A = I1(:,:,1);B = I1(:,:,2);C = I1(:,:,3);
然后可调用size()获取图像的矩阵像素大小,接着用for循环分别在行和列方向进行遍历操作,分析每一个像素点的大小,将0-255的灰度级分为三个区域,将0-100的灰度级像素点全部变为灰度级为1,将126-255的灰度级像素点全部变为灰度级为254,然后将100-125直接的灰度级像素点变为原像素点的二倍,即将该区域的灰度级进行拓展放大。

clear all
I1= imread('D:\1.jpg');          %读取图像
subplot(2,2,1),imshow(I1),title('原图');

 A = I1(:,:,1);
subplot(2,2,2),imhist(A),title('原图直方图');
 B = I1(:,:,2);
 C = I1(:,:,3);
 [rows , cols , colors] = size(I1);
 for i=1:rows
     for j=1:cols
         if A(i,j)<=100
             A(i,j)=1;
         else if A(i,j)>100&A(i,j)<=125
             A(i,j)=mod((A(i,j)*2),255);%取余
         else
              A(i,j)=254;
             end
         end
     end
 end
  for i=1:rows
     for j=1:cols
         if B(i,j)<=100
             B(i,j)=1;
          else if B(i,j)>100&B(i,j)<=125
             B(i,j)=mod((B(i,j)*2),255);
             else
              B(i,j)=254;
             end
         end
     end
  end
  for i=1:rows
     for j=1:cols
         if C(i,j)<=100
            C(i,j)=1;
       else if C(i,j)>100&C(i,j)<=125
             C(i,j)=mod((C(i,j)*2),255);
             else
             C(i,j)=254;
             end
         end
     end
  end
 D(:,:,1)=A;
 D(:,:,2)=B;
 D(:,:,3)=C;
subplot(2,2,3),imshow(D),title('分段后的图')
subplot(2,2,4),imhist(A),title('分段直方图')

变换后的图像以及直方图如下图所示:
在这里插入图片描述
由变换后的直方图可以看出,灰度级为1和254的像素点个数非常多,将原图比较均衡的直方图分段线性变换后可得到自己感兴趣灰度级放大后的图像。

1.2指数变换

指数变化与分段线性变换相似,不同点是指数变换是对整体每个像素点的灰度级进行统一的取指数变换,将整体像素点的灰度值进行变换得到新的图。

clear all
I2 = imread('D:\1.jpg');         %读取图像
I1=im2double(I2);
I1=im2double(I2);
subplot(2,3,1),imshow(I1),title('原图','fontsize',16)
 A = I1(:,:,1);
 B = I1(:,:,2);
 C = I1(:,:,3);
subplot(2,3,4),imhist(A),title('原图直方图','fontsize',16)
 [rows , cols , colors] = size(I1);
 for i=1:rows
     for j=1:cols
         A2(i,j)=A(i,j)^2;
         B2(i,j)=B(i,j)^2;
         C2(i,j)=C(i,j)^2;     
         A1(i,j)=A(i,j)^4;
         B1(i,j)=B(i,j)^4;
         C1(i,j)=C(i,j)^4;    
     end
 end
 D1(:,:,1)=A1;
 D1(:,:,2)=B1;
 D1(:,:,3)=C1;
 D2(:,:,1)=A2;
 D2(:,:,2)=B2;
 D2(:,:,3)=C2;
subplot(2,3,2),imshow(D2),title('取以2为底的指数','fontsize',16)
subplot(2,3,5),imhist(A2),title('取对数后的直方图','fontsize',16)
subplot(2,3,3),imshow(D1),title('取4为底的对数','fontsize',16)
subplot(2,3,6),imhist(A1),title('取对数后的直方图','fontsize',16)

观察得到变换后的图像及直方图如图所示:
在这里插入图片描述
由结果可以看出,随着指数的不断增大,图像趋于灰度级0的像素点个数越来越多,图像变得越来越暗。

1.3对数变换:

对数变换与指数变换方法类似,对其整体像素点的灰度值进行取对数变换

clear all
I2 = imread('D:\1.jpg');         %读取图像
I1=im2double(I2);
subplot(2,3,1),imshow(I1),title('原图','fontsize',16)
 A = I1(:,:,1);
 B = I1(:,:,2);
 C = I1(:,:,3);
subplot(2,3,4),imhist(A),title('原图直方图','fontsize',16)
 [rows , cols , colors] = size(I1);
 for i=1:rows
     for j=1:cols
         A1(i,j)=log10(A(i,j)+1);
         B1(i,j)=log10(B(i,j)+1);
         C1(i,j)=log10(C(i,j)+1);     
         A2(i,j)=log(A(i,j)+1)/log(5);
         B2(i,j)=log(B(i,j)+1)/log(5);
         C2(i,j)=log(C(i,j)+1)/log(5);  
     end
 end
 D1(:,:,1)=A1;
 D1(:,:,2)=B1;
 D1(:,:,3)=C1;
 D2(:,:,1)=A2;
 D2(:,:,2)=B2;
 D2(:,:,3)=C2;
subplot(2,3,2),imshow(D2),title('取5为底的对数','fontsize',16)
subplot(2,3,5),imhist(A2),title('取对数后的直方图','fontsize',16)
subplot(2,3,3),imshow(D1),title('取10为底的对数','fontsize',16)
subplot(2,3,6),imhist(A1),title('取对数后的直方图','fontsize',16)

得到变换后的图像及直方图如图所示:
在这里插入图片描述
观察结果发现图像越来越趋于0,图像变得越来越暗,增强一副图像中较暗部分的细节。

1.4取反变换:

clear all
I1 = imread('D:\1.jpg');         %读取图像
 A = I1(:,:,1);
 B = I1(:,:,2);
 C = I1(:,:,3);
 subplot(2,2,1),imshow(I1),title('原图','fontsize',16)
subplot(2,2,2),imhist(A),title('原图直方图','fontsize',16)
 [rows , cols , colors] = size(I1);
 for i=1:rows
     for j=1:cols
         A(i,j)=255-A(i,j);
         B(i,j)=255-B(i,j);
         C(i,j)=255-C(i,j);     
     end
 end
  
 D(:,:,1)=A;
 D(:,:,2)=B;
 D(:,:,3)=C;
subplot(2,2,3),imshow(D),title('取反','fontsize',16)
subplot(2,2,4),imhist(A),title('取反直方图','fontsize',16)

在这里插入图片描述
其直方图与原图刚好对称。

2.1图像均衡化

先将图像转换为二维的灰度图,再用for循环统计每个灰度级点的个数,并进行归一化处理,求得概率值,然后获得累计概率值,并进行相应的均衡化变化,然后分别将灰度值为0-255直接的每个像素点的灰度值改为均衡化后的灰度值,得到均衡化后的图像。

clear all
I2 = imread('D:\3.jpg');         %读取图像
I1=rgb2gray(I2);    %将彩色图转化为二维的灰度图
subplot(2,2,1),imshow(I1),title('原图','fontsize',16)
[row,col]=size(I1);   %获取图像的像素点个数
a=zeros(1,256);
a1=zeros(1,256);
for i=0:255
    a(i+1)=sum(I1(:)==i)/(row*col);  %统计每个灰度级点的个数,
                                     %并进行归一化处理,求得概率值
    a1(i+1)=sum(I1(:)==i);
end
subplot(2,2,2),bar(0:255,a1),title('原图','fontsize',16)
b=zeros(1,256);
for i=1:256   
    for j=1:i
        b(i)=b(i)+a(j);   %获得累积概率值
    end
end
c=zeros(1,256);
for i=1:256
    c(i)=round(b(i)*255);  %进行相应的变化
end
I3=I1;
for i=0:255
    I3(find(I1==i))=c(i+1);  %将灰度值为i的像素点的灰度值改为均
                             %衡化后的灰度值
end
a2=zeros(1,256);
for i=0:255
    a2(i+1)=sum(I3(:)==i);
end
subplot(2,2,3),imshow(I3),title('均衡化后的图','fontsize',16)
subplot(2,2,4),bar(0:255,a2),title('均衡化后直方图','fontsize',16)   

在这里插入图片描述
由图可以看出,通过图像均衡化处理后,可将原本不清晰的雾天图像变得较为清晰。
图像求均衡化步骤如下:
在这里插入图片描述
在这里插入图片描述

2.2直方图规定化

在这里插入图片描述
在这里插入图片描述
以上是GML映射规则,而SML映射与GML恰好相反,SML是从原始图到规定图累积分布概率值的简单的一一对应,满足:累积概率值差 最小的灰度级。
在这里插入图片描述

2019-04-25 09:35:00 weixin_30748995 阅读数 237

1.图像的傅里叶变换一(平移性质)

 傅里叶变换的平移性质表明了函数与一个指数项相乘等于将变换后的空域中心移到新的位置,并且平移不改变频谱的幅值。

I=imread('1.bmp');
figure(1)
imshow(real(I));
I=I(:,:,3);
fftI=fft2(I);
sfftI=fftshift(fftI); %求离散傅里叶频谱
%对原始图像进行二维离散傅里叶变换,并将其坐标原点移到频谱图中央位置
RRfdp1=real(sfftI);
IIfdp1=imag(sfftI);
a=sqrt(RRfdp1.^2+IIfdp1.^2);
a=(a-min(min(a)))/(max(max(a))-min(min(a)))*225;
figure(2)
imshow(real(a));
I=imread('2.bmp');
figure(1)
imshow(real(I));
I=I(:,:,3);
fftI=fft2(I);
sfftI=fftshift(fftI); %求离散傅里叶频谱
%对原始图像进行二维离散傅里叶变换,并将其坐标原点移到频谱图中央位置
RRfdp1=real(sfftI);
IIfdp1=imag(sfftI);
a=sqrt(RRfdp1.^2+IIfdp1.^2);
a=(a-min(min(a)))/(max(max(a))-min(min(a)))*225;
figure(2)
imshow(real(a));
I=imread('3.bmp');
figure(1)
imshow(real(I));
I=I(:,:,3);
fftI=fft2(I);
sfftI=fftshift(fftI); %求离散傅里叶频谱
%对原始图像进行二维离散傅里叶变换,并将其坐标原点移到频谱图中央位置
RRfdp1=real(sfftI);
IIfdp1=imag(sfftI);
a=sqrt(RRfdp1.^2+IIfdp1.^2);
a=(a-min(min(a)))/(max(max(a))-min(min(a)))*225;
figure(2)
imshow(real(a));

 实验结果符合傅里叶变换平移性质

2.图像的傅里叶变换二(旋转性质)

%构造原始图像
I=zeros(256,256);
I(88:168,124:132)=1; %图像范围是256*256,前一值是纵向比,后一值是横向比
imshow(I)
%求原始图像的傅里叶频谱
J=fft2(I);
F=abs(J);
J1=fftshift(F);figure
imshow(J1,[5 50])
%对原始图像进行旋转
J=imrotate(I,90,'bilinear','crop');
figure
imshow(J)
%求旋转后图像的傅里叶频谱
J=fft2(I);
F=abs(J);
J2=fftshift(F);figure
imshow(J2,[5 50])

 

 

3.图像的离散余弦变换一

%对cameraman.tif文件计算二维DCT变换
RGB=imread('cameraman.tif');
figure(1)
imshow(RGB)
I=rgb2gray(RGB);
%真彩色图像转换成灰度图像
J=dct2(I);
%计算二维DCT变换
figure(2)
imshow(log(abs(J)),[])
%图像大部分能量集中在左上角处
figure(3);
J(abs(J)<10)=0;
%把变换矩阵中小于10的值置换为0,然后用idct2重构图像
K=idct2(J)/255;
imshow(K)

 

4.图像的离散余弦变换二

% I=imread('1.bmp');
% figure(1)
% imshow(real(I));
% I=I(:,:,3);
% fftI=fft2(I);
% sfftI=fftshift(fftI); %求离散傅里叶频谱
% %对原始图像进行二维离散傅里叶变换,并将其坐标原点移到频谱图中央位置
% RRfdp1=real(sfftI);
% IIfdp1=imag(sfftI);
% a=sqrt(RRfdp1.^2+IIfdp1.^2);
% a=(a-min(min(a)))/(max(max(a))-min(min(a)))*225;
% figure(2)
% imshow(real(a));
% I=imread('2.bmp');
% figure(1)
% imshow(real(I));
% I=I(:,:,3);
% fftI=fft2(I);
% sfftI=fftshift(fftI); %求离散傅里叶频谱
% %对原始图像进行二维离散傅里叶变换,并将其坐标原点移到频谱图中央位置
% RRfdp1=real(sfftI);
% IIfdp1=imag(sfftI);
% a=sqrt(RRfdp1.^2+IIfdp1.^2);
% a=(a-min(min(a)))/(max(max(a))-min(min(a)))*225;
% figure(2)
% imshow(real(a));
% I=imread('3.bmp');
% figure(1)
% imshow(real(I));
% I=I(:,:,3);
% fftI=fft2(I);
% sfftI=fftshift(fftI); %求离散傅里叶频谱
% %对原始图像进行二维离散傅里叶变换,并将其坐标原点移到频谱图中央位置
% RRfdp1=real(sfftI);
% IIfdp1=imag(sfftI);
% a=sqrt(RRfdp1.^2+IIfdp1.^2);
% a=(a-min(min(a)))/(max(max(a))-min(min(a)))*225;
% figure(2)
% imshow(real(a));

% %构造原始图像
% I=zeros(256,256);
% I(88:168,124:132)=1; %图像范围是256*256,前一值是纵向比,后一值是横向比
% imshow(I)
% %求原始图像的傅里叶频谱
% J=fft2(I);
% F=abs(J);
% J1=fftshift(F);figure
% imshow(J1,[5 50])
% %对原始图像进行旋转
% J=imrotate(I,90,'bilinear','crop');
% figure
% imshow(J)
% %求旋转后图像的傅里叶频谱
% J=fft2(I);
% F=abs(J);
% J2=fftshift(F);figure
% imshow(J2,[5 50])

% %对cameraman.tif文件计算二维DCT变换
% RGB=imread('cameraman.tif');
% figure(1)
% imshow(RGB)
% I=rgb2gray(RGB);
% %真彩色图像转换成灰度图像
% J=dct2(I);
% %计算二维DCT变换
% figure(2)
% imshow(log(abs(J)),[])
% %图像大部分能量集中在左上角处
% figure(3);
% J(abs(J)<10)=0;
% %把变换矩阵中小于10的值置换为0,然后用idct2重构图像
% K=idct2(J)/255;
% imshow(K)

RGB=imread('cameraman.tif');
I=rgb2gray(RGB);
I=im2double(I); %转换图像矩阵为双精度型
T=dctmtx(8);    %产生二维DCT变换矩阵
%矩阵T及其转置T'是DCT函数P1*X*P2的参数
B=blkproc(I,[8 8],'P1*x*P2',T,T');
maxk1=[ 1 1 1 1 0 0 0 0 
        1 1 1 0 0 0 0 0
        1 1 0 0 0 0 0 0
        1 0 0 0 0 0 0 0 
        0 0 0 0 0 0 0 0
        0 0 0 0 0 0 0 0
        0 0 0 0 0 0 0 0 
        0 0 0 0 0 0 0 0 ];  %二值掩模,用来压缩DCT系数
B2=blkproc(B,[8 8],'P1.*x',mask1); %只保留DCT变换的10个系数
I2=blkproc(B2,[8 8],'P1*x*P2',T',T);    %重构图像
figure,imshow(T);
figure,imshow(B2);
figure,imshow(I2);

RGB=imread('cameraman.tif');
I=rgb2gray(RGB);
I=im2double(I); %转换图像矩阵为双精度型
T=dctmtx(8);    %产生二维DCT变换矩阵
%矩阵T及其转置T'是DCT函数P1*X*P2的参数
B=blkproc(I,[8 8],'P1*x*P2',T,T');
maxk1=[ 1 1 1 1 0 0 0 0 
        1 1 1 0 0 0 0 0
        1 0 0 0 0 0 0 0
        0 0 0 0 0 0 0 0 
        0 0 0 0 0 0 0 0
        0 0 0 0 0 0 0 0
        0 0 0 0 0 0 0 0 
        0 0 0 0 0 0 0 0 ];  %二值掩模,用来压缩DCT系数
B2=blkproc(B,[8 8],'P1.*x',mask1); %只保留DCT变换的10个系数
I2=blkproc(B2,[8 8],'P1*x*P2',T',T);    %重构图像
figure,imshow(T);
figure,imshow(B2);
figure,imshow(I2);

 

5.图像的哈达玛变换

cr=0.5;
I=imread('cameraman.tif');
I=im2double(I)/255; %将读入的unit8类型的RGB图像I转换为double类型的数据
figure(1),imshow(I);%显示
                    %求图像大小
[m_I,n_I]=size(I);  %提取矩阵I的行列数,m_I为I的行数,n_I为I的列数
sizi=8;
snum=64;
%分块处理
t=hadamard(sizi) %生成8*8的哈达码矩阵
hdcoe=blkproc(I,[sizi sizi],'P1*x*P2',t,t');
                 %将图片分成8*8像素块进行哈达码变换
                 %重新排列系数
CE=im2col(hdcoe,[sizi,sizi],'distinct');
    %将矩阵hdcode分为8*8互不重叠的子矩阵,再将每个子矩阵作为CE的一列
[Y Ind]=sort(CE); %对CE进行升序排序
                  %舍去方差较小的系数,保留原系数的二分之一,即32个系数
[m,n]=size(CE);%提取矩阵CE的行列数,m为CE的行数,n为CE的列数
snum=snum-snum*cr;
for i=1:n
CE(Ind(1:snum),i)=0;
end
%重建图像
re_hdcoe=col2im(CE,[sizi,sizi],[m_I,n_I],'distinct');
                  %将矩阵的列重新组织到块中
re_I=blkproc(re_hdcoe,[sizi sizi],'P1*x*P2',t',t);
                  %进行反哈达码变换,得到压缩后的图像
re_I=double(re_I)/64; %转换为double类型的数据
figure(2);
imshow(re_I);

%计算原始图像和压缩后图像的误差
error=I.^2-re_I.^2;
MSE=sum(error(:))/prod(size(re_I));



 

转载于:https://www.cnblogs.com/zhying99/p/10766446.html

2007-08-24 14:09:00 antheazhang 阅读数 1291

参考《Visual C++数字图像处理典型算法及实现 》中的源代码,按照matlab中的程序做了修改,并用matlab进行了分解及重构的验证。

局限性:该算法仅对输入数据长度为2的指数的情况有效。

int Log2(int x)
{//求最大可分解尺度,不要随便用math.h中的函数,因为各种重载过于复杂,极可能出错
 int k=1;
 while((1<<k)<=x) k++;
 k--;
 return k;
}

BOOL DWTStep_1D(double* data,int nCurLevel,int nInv,int nStep,int nSupp)
{
 //double s=sqrt((double)2);
 //获得小波基的指针
 double* h=(double*)hCoef[nSupp-1];//系数为Lo_R
 ASSERT(nCurLevel>=0);
 //计算当前层数的长度
 int CurN=1<<nCurLevel;
 if(nInv) CurN<<=1;
 if(nSupp<1||nSupp>10||CurN<2*nSupp)
  return FALSE;
 //分配内存存放结果
 double* ptemp=new double[CurN];
 if(!ptemp) return FALSE;
 double s1,s2;
 int Index1,Index2;
 //判断是进行DWT还是进行IDWT
 if(!nInv)
 {//DWT
  //对称延拓
  int ExtN=2*nSupp+CurN;//延拓后的长度
  double* pdata=new double[ExtN];
  for(int i=0;i<nSupp;i++)
  {
   pdata[i]=data[nSupp-1-i];
   pdata[ExtN-nSupp+i]=data[CurN-1-i];
  }
  for(int i=nSupp;i<ExtN-nSupp;i++)
   pdata[i]=data[i-nSupp];

  //分解及系数提取
  Index1=0;
  Index2=2*nSupp-1;
  for(int i=0;i<CurN/2;i++)
  {
   s1=s2=0;
   double t=-1;
   for(int j=0;j<2*nSupp;j++,t=-t)
   {
    s1+=h[j]*pdata[(Index1)*nStep];
    s2+=t*h[j]*pdata[(Index2)*nStep];
    Index1++;
    Index2--;
   }
   ptemp[i]=s1;
   ptemp[i+CurN/2]=s2;
   Index1-=2*nSupp;
   Index2+=2*nSupp;
   Index1+=2;//downsample,隔一个采样一次
   Index2+=2;
  }
  delete[] pdata;
 }
 else
 {//IDWT
  //卷积零延拓
  double* pdatal=new double[nSupp+CurN/2+1];
  double* pdatah=new double[nSupp+CurN/2+1];
  int bn=nSupp/2;
  for(int i=0;i<bn;i++)
  {//零延拓数据前端
   pdatal[i]=0;
   pdatah[i]=0;
  }
  for(int i=CurN/2+bn;i<nSupp+CurN/2+1;i++)
  {//零延拓数据后端
   pdatal[i]=0;
   pdatah[i]=0;
  }
  for(int i=0;i<CurN/2;i++)
  {//拷贝中间数据
   pdatal[bn+i]=data[i];
   pdatah[bn+i]=data[CurN/2+i];
  }

  //重构并提取系数
  Index1=nSupp;//逆序乘积(正序卷积)
  for(int i=0;i<CurN/2;i++)
  {
   s1=s2=0;
   int Index3=0;
   int Index4=2*nSupp-2;
   
   if(nSupp%2==0)
   {
    for(int j=0;j<nSupp;j++)
    {
     s1+=h[Index3]*pdatal[Index1*nStep]+h[Index4+1]*pdatah[Index1*nStep];
     s2+=h[Index3+1]*pdatal[Index1*nStep]-h[Index4]*pdatah[Index1*nStep];
     Index3+=2;
     Index4-=2;
     Index1--;
    }
    ptemp[2*i]=s1;
    ptemp[2*i+1]=s2;
   }
   if(nSupp%2==1)
   {
    for(int j=0;j<nSupp;j++)
    {
     s1+=h[Index3]*pdatal[Index1*nStep]+h[Index4+1]*pdatah[Index1*nStep];
     s2+=h[Index3+1]*pdatal[(Index1-1)*nStep]-h[Index4]*pdatah[(Index1-1)*nStep];
     Index3+=2;
     Index4-=2;
     Index1--;
    }
    ptemp[2*i]=s2;
    ptemp[2*i+1]=s1;
   }
   Index1+=nSupp;
   Index1++;
  }
  delete[] pdatal;
  delete[] pdatah;
 }
 for(int i=0;i<CurN;i++)
  data[i*nStep]=ptemp[i];
 //删除分配的临时内存
 delete[] ptemp;
 return TRUE;
}
BOOL DWT_1D(double* data,int nMaxLevel,int nDWTSteps,int nInv,int nStep,int nSupp)
{
 //计算最小可分解的层数
 int MinLevel=nMaxLevel-nDWTSteps;
 //判断是否为DWT
 if(!nInv)
 {//DWT
  int n=nMaxLevel;
  while(n>MinLevel)
   if(!DWTStep_1D(data,n--,nInv,nStep,nSupp))
    return FALSE;
 }
 else
 {//IDWT
  int n=MinLevel;
  while(n<nMaxLevel)
   if(!DWTStep_1D(data,n++,nInv,nStep,nSupp))
    return FALSE;
 }
 return TRUE;
}

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