2014-12-07 10:37:41 twobqn123 阅读数 483
  • MATLAB基础知识大串讲

    Matlab基础知识大串讲,具体内容包括matlab下载安装、数据类型、矩阵操作、运算符、字符串处理、数组运算、M文件、变量、控制流、脚本与函数、图形绘制、二维图形绘制、三维图形绘制、四维图形绘制。

    33019 人正在学习 去看看 魏伟
1.使用模板处理图像相关概念:     

      模板:矩阵方块,其数学含义是卷积运算。
      卷积运算:可看作是加权求和的过程,使用到的图像区域中的每个像素分别于卷积核(权矩阵)的每个元素对应相
                乘,所有乘积之和作为区域中心像素的新值。
      卷积核:卷积时使用到的权用一个矩阵表示,该矩阵使用的图像区域大小相同,其行、列都是奇数,
              是一个权矩阵。
      卷积示例:
              3 * 3 的像素区域R与卷积核G的卷积运算:
              R5(中心像素)=R1G1 + R2G2 + R3G3 + R4G4 + R5G5 + R6G6 + R7G7 + R8G8 + R9G9
            

2.使用模板处理图像的问题:
       边界问题:当处理图像边界像素时,卷积与图像使用区域不能匹配,卷积核的中心边界像素点对应,
                 卷积运算将出现问题。
       处理办法:
              A. 忽略边界像素,即处理后的图像将丢掉这些像素。
              B. 保留原边界像素,即copy边界像素到处理后的图像

3.常用模板


如果你刚刚接触图像处理,或者离开大学很长时间,看到卷积这个东西,肯定和我样感到晕菜.那么就复习下,并且实际的写个程序验证下,我保证你这辈子不会再忘记卷积的概念了.我们来看卷积的概念.
连续空间的卷积定义是 f(x)g(x)的卷积是 f(t-x)g(x) 在t从负无穷到正无穷的积分值.t-x要在f(x)定义域内,所以看上去很大的积分实际上还是在定范围的.
实际的过程就是f(x) 先做一个Y轴的反转,然后再沿X轴平移t就是f(t-x),然后再把g(x)拿来,两者乘积的值再积分.想象下如果g(x)或者f(x)是个单位的阶越函数. 那么就是f(t-x)g(x)相交部分的面积.这就是卷积了.
把积分符号换成求和就是离散空间的卷积定义了.那么在图像卷积卷积地是什么意思呢,就是图像就是图像f(x),模板是g(x),然后将模版g(x)在模版中移动,每到一个位置,就把f(x)g(x)的定义域相交的元素进行乘积并且求和,得出新的图像一点,就是被卷积后的图像. 模版又称为卷积核.卷积核做一个矩阵的形状.
卷积定义上是线性系统分析经常用到的.线性系统就是一个系统的输入和输出的关系是线性关系.就是说整个系统可以分解成N多的无关独立变化,整个系统就是这些变化的累加.
如 x1->y1, x2->y2; 那么A*x1 + B*x2 -> A*y1 + B*y2 这就是线性系统. 表示一个线性系统可以用积分的形式 如 Y = Sf(t,x)g(x)dt S表示积分符号,就是f(t,x)表示的是A B之类的线性系数.
看上去很像卷积呀,,对如果f(t,x) = F(t-x) 不就是了吗.从f(t,x)变成F(t-x)实际上是说明f(t,x)是个线性移不变,就是说 变量的差不变化的时候,那么函数的值不变化. 实际上说明一个事情就是说线性移不变系统的输出可以通过输入和表示系统线性特征的函数卷积得到.

2017-07-28 13:50:23 TchChan 阅读数 2017
  • MATLAB基础知识大串讲

    Matlab基础知识大串讲,具体内容包括matlab下载安装、数据类型、矩阵操作、运算符、字符串处理、数组运算、M文件、变量、控制流、脚本与函数、图形绘制、二维图形绘制、三维图形绘制、四维图形绘制。

    33019 人正在学习 去看看 魏伟

模板:矩阵方块,其数学含义是一种卷积运算

卷积运算:可看做是加权求和的过程,使用到的图像区域中的每个像素分别于卷积核(权矩阵)的每个元素对应相乘,所有乘机之和作为区域中心像素的新值。

利用卷积可以实现对图像模糊处理,边缘检测,产生轧花效果的图像。

卷积核:卷积时用到的权用一个矩阵表示,该矩阵与使用的图像区域大小相同,其行列都是奇数(这一点很重要)

举个例子:

一个3*3的像素区域R与卷积核G的卷积运算:

R5(中心像素)=R1G1+R2G2+R3G3+R4G4+R5G5+R6G6+R7G7+R8G8+R9G9


下篇将说明一下卷积运算遇到的问题和几种处理办法以及模板






2019-10-24 21:51:50 wujuxKkoolerter 阅读数 84
  • MATLAB基础知识大串讲

    Matlab基础知识大串讲,具体内容包括matlab下载安装、数据类型、矩阵操作、运算符、字符串处理、数组运算、M文件、变量、控制流、脚本与函数、图形绘制、二维图形绘制、三维图形绘制、四维图形绘制。

    33019 人正在学习 去看看 魏伟

01-图像降噪-平滑滤波-模板操作

1 模板操作

模板操作实现一种邻域运算,即某个像素点的结果不仅和本图像的灰度有关,而且和其邻域点的值有关。模板运算在数学上其实就是卷积运算。卷积处理的过程如下:

在这里插入图片描述
卷积运算中的卷积核就是模板运算中的模板,卷积就是做加权求和的过程。邻域中的每个像素分别与卷积核中的每一个元素相乘,乘积求和所得结果即为中心像素的新值。卷积核中的元素称作加权系数(亦称为卷积系数),改变卷积核中的加权系数会影响到总和的数值与符号,从而影响到所求像素的新值。

2 掩模消噪法

掩模消噪法可以用于消除随机噪声,是一种常用的线性低通滤波器,也称为均值滤波器。常见的模板有:

$
H_1 = \frac{1}{10} \begin{bmatrix}
1 & 1 & 1 \
1 & 2 & 1 \
1 & 1 & 1
\end{bmatrix}
$,
$
H_2 = \frac{1}{16} \begin{bmatrix}
1 & 2 & 1 \
2 & 4 & 2 \
1 & 2 & 1
\end{bmatrix}
$,
$
H_3 = \frac{1}{8} \begin{bmatrix}
1 & 1 & 1 \
1 & 0 & 1 \
1 & 1 & 1
\end{bmatrix}
$

如果模板的作用域越大,平滑作用就越明显,图像越模糊。

Python实现的代码如下:

import numpy as np
import scipy.signal as signal
%matplotlib inline
import matplotlib.pyplot as plt
import imageio
def convolve2d(img,fil,mode = 'same'):                #分别提取三个通道
    
    if mode == 'fill':
        h = fil.shape[0] // 2
        w = fil.shape[1] // 2
        img = np.pad(img, ((h, h), (w, w),(0, 0)), 'constant')
    conv_b = _convolve2d(img[:,:,0],fil)              #然后去进行卷积操作
    conv_g = _convolve2d(img[:,:,1],fil)
    conv_r = _convolve2d(img[:,:,2],fil)

    dstack = np.dstack([conv_b,conv_g,conv_r])      #将卷积后的三个通道合并
    return dstack                                   #返回卷积后的结果

def _convolve2d(img,fil):         
    
    fil_heigh = fil.shape[0]                        #获取卷积核(滤波)的高度
    fil_width = fil.shape[1]                        #获取卷积核(滤波)的宽度
    
    conv_heigh = img.shape[0] - fil.shape[0] + 1    #确定卷积结果的大小
    conv_width = img.shape[1] - fil.shape[1] + 1

    conv = np.zeros((conv_heigh,conv_width),dtype = 'uint8')
    
    for i in range(conv_heigh):
        for j in range(conv_width):                 #逐点相乘并求和得到每一个点
            conv[i][j] = wise_element_sum(img[i:i + fil_heigh,j:j + fil_width ],fil)
    return conv
    
def wise_element_sum(img,fil):
    res = (img * fil).sum() 
    if(res < 0):
        res = 0
    elif res > 255:
        res  = 255
    return res
src = imageio.imread('../../../../resources/images/f1.jpg')
kernel = np.array([[1.0,1.0,1.0],[1.0,2.0,1.0],[1.0,1.0,1.0]]) / 10.0

result = convolve2d(src,kernel,'fill')

原图像

plt.imshow(src)

在这里插入图片描述

程序运行结果

plt.imshow(result)

在这里插入图片描述

2012-12-17 23:16:42 wuyou_365 阅读数 486
  • MATLAB基础知识大串讲

    Matlab基础知识大串讲,具体内容包括matlab下载安装、数据类型、矩阵操作、运算符、字符串处理、数组运算、M文件、变量、控制流、脚本与函数、图形绘制、二维图形绘制、三维图形绘制、四维图形绘制。

    33019 人正在学习 去看看 魏伟

模板运算在图像处理中非常普遍,模板运算普遍运算量大,但可以通过避免其中许多重复的运算达到优化的效果,以下以krisch算子为例来说明如何避免重复运算,krisch算子包含8个3x3模板:

具体运算过程是对于源图像的每一个像素和它的8邻域与以上8个模板进行运算,共得出8个值,取其中最大的值作为该像素的最终值。

int cvKirsch(unsigned char* srcarr, unsigned char* dstarr, unsigned char* angle_mask, int width, int height)
{
	int i, j, k, l, m, n;
	unsigned char* _srcarr, *_dstarr, *_mask;

	//表示某一像素8邻域和该像素点的值
	int v00, v01, v10, v11, v20, v21, v30, v31, v40, v41, v50, v51, v60, v61, v70, v71, v80, v81; 
	
	//分别表示每一个模板计算出的该点像素值,最大者则为该点最终值
	int m0, m1, m2, m3, m4, m5, m6, m7;

	/*以下定义用于保存每一个列向量运算出的值,v0_5n3n3表示算子中第1列向量是(5,-3,-3),
	包含v0_5n3n3的算子有第1个算子v1_50n3表示算子中第2列向量是(5,0,-3),
	符合这个条件的有第1,2,8这3个算子;所以m0 = v0_5n3n3 + v1_50n3 + v2_5n3n3
	以此类推*/
	int v0_5n3n3, v1_50n3, v2_5n3n3; //M0
	int v0_n3n3n3, v2_55n3;//M1 
	int v1_n30n3, v2_555; //M2
	int v1_n305, v2_n355; //M3
	int v0_n3n35, v2_n3n35;  //M4
	int v0_n355, v2_n3n3n3;  //M5
	int v0_555;  //M6
	int  v0_55n3;  //M7 
	
	int max;
	
	_srcarr = srcarr;
	_dstarr = dstarr;
	_mask = angle_mask;
	m = height - 1;
	n = width - 1;
	
	for(i = 1;i < m;i++)
	{
		_srcarr += width;
		_dstarr += width;
		_mask += width;
	
		//计算每个元素的值		
		k = -width;
		l = _srcarr[k];
		v00 = l*5;
		v01 = l*3;
		k ++;
		l = _srcarr[k];
		v10 = l*5;
		v11 = l*3;			
		k ++;
		l = _srcarr[k];
		v20 = l*5;
		v21 = l*3;

		k = 0;
		l = _srcarr[k];
		v30 = l*5;
		v31 = l*3;
		k ++;
		l = _srcarr[k];
		v40 = l*5;
		v41 = l*3;				
		k ++;
		l = _srcarr[k];
		v50 = l*5;
		v51 = l*3;	

		k = width;
		l = _srcarr[k];
		v60 = l*5;
		v61 = l*3;	
		k ++;
		l = _srcarr[k];
		v70 = l*5;
		v71 = l*3;	
		k ++;													 
		l = _srcarr[k];
		v80 = l*5;
		v81 = l*3;
		
		//计算列值
		//M0
		v0_5n3n3 = 	v00-v31-v61;
		v1_50n3 = v10-v71;
		v2_5n3n3 = v20-v51-v81;
		
		// M1
		v0_n3n3n3 = -v01-v31-v61;
		v2_55n3 = v20+v50-v81;
		
		// M2
		v1_n30n3 = -v11-v71;
		v2_555 = v20+v50+v80;
		
		// M3
		v1_n305 = -v11+v70;
		v2_n355 = -v21+v50+v80;
		
		// M4
		v0_n3n35 = -v01-v31+v60;
		v2_n3n35 = -v21-v51+v80;
		
		//M5
		v0_n355 = -v01+v30+v60;
		v2_n3n3n3 = -v21-v51-v81;
		
		//M6
		v0_555 = v00+v30+v60;
		
		//M7
		v0_55n3 = v00+v30-v61;
		
		//计算每个模板的值
		max = 0;
		m0 = abs(v0_5n3n3 + v1_50n3 + v2_5n3n3);
		if(m0 > max)
		{
			max = m0;
			_mask[1] = 0;
		}
		/*m1的第2列值v1_50n3之前计算过了,这里可避免重复计算。
		以下计算m2-m7有重复列的都可以避免重复计算*/
		m1 = abs(v0_n3n3n3 + v1_50n3 + v2_55n3);
		if(m1 > max)
		{
			max = m1;
			_mask[1] = 1;
		}
		m2 = abs(v0_n3n3n3 + v1_n30n3 + v2_555);
		if(m2 > max)
		{
			max = m2;
			_mask[1] = 2;
		}
		m3 = abs(v0_n3n3n3 + v1_n305 + v2_n355);
		if(m3 > max)
		{
			max = m3;
			_mask[1] = 3;
		}
		m4 = abs(v0_n3n35 + v1_n305 + v2_n3n35);
		if(m4 > max)
		{
			max = m4;
			_mask[1] = 4;
		}
		m5 = abs(v0_n355 + v1_n305 + v2_n3n3n3);
		if(m5 > max)
		{
			max = m5;
			_mask[1] = 5;
		}
		m6 = abs(v0_555 + v1_n30n3 + v2_n3n3n3);
		if(m6 > max)
		{
			max = m6;
			_mask[1] = 6;
		}
		m7 = abs(v0_55n3 + v1_50n3 + v2_n3n3n3);
		if(m7 > max)
		{
			max = m7;
			_mask[1] = 7;
		}
		_dstarr[1] = (max > 255) ? 255 : max;					
		
		for(j = 2;j < n;j++)
		{	
			/*计算每个像素的值,这里个别点可以使用计算前一个像素时的值,
			避免重复计算
			v0 v1 v2
			v3 v4 v5
			v6 v7 v8
			可以看出,计算下一个像素时,整体向右移1列,新的(v0,v3,v6)的值
			就是计算上一个像素时的(v1,v4,v7)的值
			*/
			v00 = v10;																				
			v01 = v11;
			v30 = v40;
			v31 = v41;
			v60 = v70;
			v61 = v71;
			
			v10 = v20;
			v11 = v21;	
			v40 = v50;
			v41 = v51;
			v70 = v80;
			v71 = v81;		

			k = -width+1+j;
			l = _srcarr[k];
			v20 = l*5;
			v21 = l*3;

			k = 1+j;
			l = _srcarr[k];
			v50 = l*5;
			v51 = l*3;	

			k = 1+j+width;
			l = _srcarr[k];
			v80 = l*5;
			v81 = l*3;						
		
			//计算列值
			// 0
			v0_5n3n3 = 	v00-v31-v61;
			v1_50n3 = v10-v71;
			v2_5n3n3 = v20-v51-v81;
			
			// 1
			v0_n3n3n3 = -v01-v31-v61;
			v2_55n3 = v20+v50-v81;
			
			// 2
			v1_n30n3 = -v11-v71;
			v2_555 = v20+v50+v80;
			
			// 3
			v1_n305 = -v11+v70;
			v2_n355 = -v21+v50+v80;
			
			// 4
			v0_n3n35 = -v01-v31+v60;
			v2_n3n35 = -v21-v51+v80;
			
			// 5
			v0_n355 = -v01+v30+v60;
			v2_n3n3n3 = -v21-v51-v81;
			
			// 6
			v0_555 = v00+v30+v60;
			
			// 7
			v0_55n3 = v00+v30-v61;
			
			//计算每个模板的值
			max = 0;
			m0 = abs(v0_5n3n3 + v1_50n3 + v2_5n3n3);
			if(m0 > max)
			{
				max = m0;
				_mask[j] = 0;
			}
			m1 = abs(v0_n3n3n3 + v1_50n3 + v2_55n3);
			if(m1 > max)
			{
				max = m1;
				_mask[j] = 1;
			}
			m2 = abs(v0_n3n3n3 + v1_n30n3 + v2_555);
			if(m2 > max)
			{
				max = m2;
				_mask[j] = 2;
			}
			m3 = abs(v0_n3n3n3 + v1_n305 + v2_n355);
			if(m3 > max)
			{
				max = m3;
				_mask[j] = 3;
			}
			m4 = abs(v0_n3n35 + v1_n305 + v2_n3n35);
			if(m4 > max)
			{
				max = m4;
				_mask[j] = 4;
			}
			m5 = abs(v0_n355 + v1_n305 + v2_n3n3n3);
			if(m5 > max)
			{
				max = m5;
				_mask[j] = 5;
			}
			m6 = abs(v0_555 + v1_n30n3 + v2_n3n3n3);
			if(m6 > max)
			{
				max = m6;
				_mask[j] = 6;
			}
			m7 = abs(v0_55n3 + v1_50n3 + v2_n3n3n3);
			if(m7 > max)
			{
				max = m7;
				_mask[j] = 7;
			}
			_dstarr[j] = (max > 255) ? 255 : max;
		}
	}
	return 0;
}



对于高斯算子、索伯算子等,也可用相同的方法,避免重复计算。

                                
2018-01-21 20:11:06 Tomnyy 阅读数 141
  • MATLAB基础知识大串讲

    Matlab基础知识大串讲,具体内容包括matlab下载安装、数据类型、矩阵操作、运算符、字符串处理、数组运算、M文件、变量、控制流、脚本与函数、图形绘制、二维图形绘制、三维图形绘制、四维图形绘制。

    33019 人正在学习 去看看 魏伟
模板运算:
包含一幅或多幅图像的阵列操作是以逐像素为基础执行的,图像可以等价的被看成是矩阵。
模板通常是NxN(N通常为3、5、7、9等很小的奇数)的矩阵。模板运算是用各种现成的模板对图像进行处理从而获得需要的图像。其基本思路就是将原图像中的某个像素的值作为他本身灰度值和其相邻像素灰度值的函数。模板中存在有一个锚点(anchor point),通常是矩阵中心点,和原图像中带计算的点对应;整个模板对应的区域就是原图像中的像素点的相邻区域。
常见的函数操作有卷积和排序两种。
卷积:可以看作是加权求和的过程,令用到的图像区域中的每个像素分别和卷积核(即模板)相乘,将所有乘积之和作为区域中心像素的新值。
常用模板:

参考链接:http://blog.csdn.net/xiaoxin_ling/article/details/3587987 https://www.cnblogs.com/zjutzz/p/4854839.html  

 边缘检测:
步骤
      canny函数用例:
//---------------------------------【头文件、命名空间包含部分】----------------------------
//		描述:包含程序所使用的头文件和命名空间
//------------------------------------------------------------------------------------------------
#include <opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;


//-----------------------------------【main( )函数】-------------------------------------------
//            描述:控制台应用程序的入口函数,我们的程序从这里开始
//-----------------------------------------------------------------------------------------------
int main( )
{
	//载入原始图  
	Mat srcImage = imread("1.jpg");  //工程目录下应该有一张名为1.jpg的素材图
	Mat srcImage1=srcImage.clone();

	//显示原始图 
	imshow("【原始图】Canny边缘检测", srcImage); 

	//----------------------------------------------------------------------------------
	//	一、最简单的canny用法,拿到原图后直接用。
	//	注意:此方法在OpenCV2中可用,在OpenCV3中已失效
	//----------------------------------------------------------------------------------
 	//Canny( srcImage, srcImage, 150, 100,3 );
	//imshow("【效果图】Canny边缘检测", srcImage); 


	//----------------------------------------------------------------------------------
	//	二、高阶的canny用法,转成灰度图,降噪,用canny,最后将得到的边缘作为掩码,拷贝原图到效果图上,得到彩色的边缘图
	//----------------------------------------------------------------------------------
	Mat dstImage,edge,grayImage;

	// 【1】创建与src同类型和大小的矩阵(dst)
	dstImage.create( srcImage1.size(), srcImage1.type() );

	// 【2】将原图像转换为灰度图像
	cvtColor( srcImage1, grayImage, COLOR_BGR2GRAY );

	// 【3】先用使用 3x3内核来降噪
	blur( grayImage, edge, Size(3,3) );

	// 【4】运行Canny算子
	Canny( edge, edge, 3,9,3 );

	//【5】将g_dstImage内的所有元素设置为0
	dstImage = Scalar::all(0);

	//【6】使用Canny算子输出的边缘图g_cannyDetectedEdges作为掩码,来将原图g_srcImage拷到目标图g_dstImage中
	srcImage1.copyTo( dstImage, edge);

	//【7】显示效果图 
	imshow("【效果图】Canny边缘检测2", dstImage); 
	waitKey(0); 
	return 0; 
}
sobel函数:
//---------------------------------【头文件、命名空间包含部分】----------------------------
//		描述:包含程序所使用的头文件和命名空间
//------------------------------------------------------------------------------------------------


//-----------------------------------【头文件包含部分】---------------------------------------
//            描述:包含程序所依赖的头文件
//----------------------------------------------------------------------------------------------
#include <opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>

//-----------------------------------【命名空间声明部分】---------------------------------------
//            描述:包含程序所使用的命名空间
//-----------------------------------------------------------------------------------------------
using namespace cv;
//-----------------------------------【main( )函数】--------------------------------------------
//            描述:控制台应用程序的入口函数,我们的程序从这里开始
//-----------------------------------------------------------------------------------------------
int main( )
{
	//【0】创建 grad_x 和 grad_y 矩阵
	Mat grad_x, grad_y;
	Mat abs_grad_x, abs_grad_y,dst;

	//【1】载入原始图  
	Mat src = imread("1.jpg");  //工程目录下应该有一张名为1.jpg的素材图

	//【2】显示原始图 
	imshow("【原始图】sobel边缘检测", src); 

	//【3】求 X方向梯度
	Sobel( src, grad_x, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT );
	convertScaleAbs( grad_x, abs_grad_x );
	imshow("【效果图】 X方向Sobel", abs_grad_x); 

	//【4】求Y方向梯度
	Sobel( src, grad_y, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT );
	convertScaleAbs( grad_y, abs_grad_y );
	imshow("【效果图】Y方向Sobel", abs_grad_y); 

	//【5】合并梯度(近似)
	addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dst );
	imshow("【效果图】整体方向Sobel", dst); 
	waitKey(0); 
	return 0; 
}


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