2018-12-17 09:10:00 weixin_30847939 阅读数 12
  • 图像处理的几种方法 1.使用skimage
    name details name details name details
    astronaut 宇航员图片 coffee 一杯咖啡图片 lena lena图片
    camera 拿相机的人图片 coins 硬币 moon 月亮
    checkerboard 棋盘 horse page 一页书
    chelsea 小猫图片 hubble_deep_field 星空 text 文字
    clock 时钟 immunohistochemistry 结肠    
    import numpy as np
    import scipy
    import matplotlib.pyplot as plt
    from skimage import io,data
    img=data.chelsea()
    img=io.imread('d:/python/loli.jpg')
    #读取图片
    # img=io.imread('d:/python/loli.jpg',as_grey=True)
    #图片变换
    [m,n,l]=img.shape
    img1=skimage.transform.resize(img,(int(m*0.6),int(n*0.6),l),mode='reflect')
    #保存图片
    io.imsave('d:/python/loli1.jpg',img1)
    io.imshow(img1)
    plt.show()
    # 显示图片信息
    print (type(img))  #显示类型
    print (img.shape)  #显示尺寸
    print (img.shape[0])  #图片宽度
    print (img.shape[1])  #图片高度
    print (img.shape[2])  #图片通道数
    print (img.size)   #显示总像素个数
    print (img.max())  #最大像素值
    print (img.min())  #最小像素值
    print (img.mean()) #像素平均值
    C:\ProgramData\Anaconda2\lib\site-packages\skimage\util\dtype.py:122: UserWarning: Possible precision loss when converting from float64 to uint8
      .format(dtypeobj_in, dtypeobj_out))
    

    <type 'numpy.ndarray'>
    (415L, 518L, 3L)
    415
    518
    3
    644910
    255
    0
    111.793140128
    
    2 使用scipy.misc(miscellaneous routines)不推荐,很多已经deprecated

    Various utilities that don’t have another home.
    Note that Pillow (https://python-pillow.org/) is not a dependency of SciPy, but the image manipulation functions indicated in the list below are not available without it.

    Deprecated functions:

    col 1 col 2
    bytescale(*args, **kwds) bytescale is deprecated!
    fromimage(*args, **kwds) fromimage is deprecated!
    imfilter(*args, **kwds) imfilter is deprecated!
    imread(*args, **kwds) imread is deprecated!
    imresize(*args, **kwds) imresize is deprecated!
    imrotate(*args, **kwds) imrotate is deprecated!
    imsave(*args, **kwds) imsave is deprecated!
    imshow(*args, **kwds) imshow is deprecated!
    toimage(*args, **kwds) toimage is deprecated!
    from scipy import misc
    import matplotlib.pyplot as plt
    import numpy as np
    # 读取图片
    img=misc.imread('d:/python/loli.jpg',mode='RGB')
    # 改变大小
    img1=scipy.misc.imresize(img,(111,80),interp='nearest')
    # 显示图片
    #misc.imshow(img) have been deprecated
    plt.imshow(img)
    plt.show()
    misc.imsave('d:/python/loli1.jpg',img)

    3 使用PIL做图像处理

    3.1 Reading and Writing Images : open( infilename ) , save( outfilename )

    3.2 Cutting and Pasting and Merging Images :

    crop() : 从图像中提取出某个矩形大小的图像。它接收一个四元素的元组作为参数,各元素为(left, upper, right, lower),坐标系统的原点(0, 0)是左上角。
    paste() :
    merge()

    3.3 几何变换

     box = (100, 100, 200, 200)
     region = im.crop(box)
     region.show()
     region = region.transpose(Image.ROTATE_180)
     region.show()
     im.paste(region, box)
     im.show()
    #旋转一幅图片
    def roll(image, delta):
        "Roll an image sideways"
    
        xsize, ysize = image.size
    
        delta = delta % xsize
        if delta == 0: return image
    
        part1 = image.crop((0, 0, delta, ysize))
        part2 = image.crop((delta, 0, xsize, ysize))
        image.paste(part2, (0, 0, xsize-delta, ysize))
        image.paste(part1, (xsize-delta, 0, xsize, ysize))
    
        return image
    #简单的几何变换
    out = im.resize((128, 128))                     #
    out = im.rotate(45)                             #逆时针旋转 45 度角。
    out = im.transpose(Image.FLIP_LEFT_RIGHT)       #左右对换。
    out = im.transpose(Image.FLIP_TOP_BOTTOM)       #上下对换。
    out = im.transpose(Image.ROTATE_90)             #旋转 90 度角。
    out = im.transpose(Image.ROTATE_180)            #旋转 180 度角。
    out = im.transpose(Image.ROTATE_270)            #旋转 270 度角。
    from PIL import Image
    im=Image.open('d:/python/loli.jpg')
    print im.format,im.size,im.mode
    im.show()
    JPEG (518, 415) RGB
    
    box = (100, 100, 200, 200)
    region = im.crop(box)
    region.show()
    region = region.transpose(Image.ROTATE_180)
    region.show()
    im.paste(region, box)
    im.show()
    out = im.resize((128, 128))                     #
    out = im.rotate(45)                             #逆时针旋转 45 度角。
    out = im.transpose(Image.FLIP_LEFT_RIGHT)       #左右对换。
    out = im.transpose(Image.FLIP_TOP_BOTTOM)       #上下对换。
    out = im.transpose(Image.ROTATE_90)             #旋转 90 度角。
    out = im.transpose(Image.ROTATE_180)            #旋转 180 度角。
    out = im.transpose(Image.ROTATE_270) 
    out.show()
  • 以上是图像处理的几种方法的内容,更多 图像处理 python 的内容,请您使用右上方搜索功能获取相关信息。

转载于:https://www.cnblogs.com/TendToBigData/p/10501154.html

2012-03-21 17:09:52 smells2 阅读数 9689

本章所涉及的方法有:灰度化彩色图像,将图像转换为ASNII码文件,直方图均衡化,伽马校正,哈尔小波变换。

0.知识储备

这里我们处理的是bmp格式的图像,bmp格式的文件有3个文件头,第一个文件头大小为14个字节,主要是对整个文件的信息的存储。

typedef struct tagBITMAPFILEHEADER {
        WORD    bfType;
        DWORD   bfSize;
        WORD    bfReserved1;
        WORD    bfReserved2;
        DWORD   bfOffBits;
} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;

第二个文件头大小为50个字节,主要存储了图像的信息,比如,图像有多少行,多少列,大小等等。

typedef struct tagBITMAPINFOHEADER{
        DWORD      biSize;
        LONG       biWidth;
        LONG       biHeight;
        WORD       biPlanes;
        WORD       biBitCount;
        DWORD      biCompression;
        DWORD      biSizeImage;
        LONG       biXPelsPerMeter;
        LONG       biYPelsPerMeter;
        DWORD      biClrUsed;
        DWORD      biClrImportant;
} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;

第三个文件头,是图像的调色板,这里我们使用的文件是24位真彩,所以没有调色板,这个文件头不存在,所以我就不列在下面了。

注意:bmp格式图像数据是倒着存贮的,具体可以参考百度百科http://baike.baidu.com/view/7671.htm#2


1.将彩色图像转换为灰度图像

我们都知道,图像是一像素为单位的,一个像素有三个色彩分量组成,即RGB(红绿蓝),每一个分量由8位(一个字节)组成,范围是0-255 。灰度图像可由彩色图像转化,可以使用公式gray = 0.3*red+0.59*green+0.11*blue,并且三个分量的值相等,即red = gray,green=gray,blue=gray。那么,我们的图像就变成了灰度图像。

/********************************************
 *	   将文件转换成灰度图像		    *
 ********************************************/
int CBitMapFile::turn2Gray()
{
	if (m_imageArray == NULL)
	{
		return -2;
	}
	
	for (int i =0,j= 0,k=0;i<m_sizeImage;)
	{
		//转换为灰度图像,注意填充的字节
		BYTE blue,green,red,gray;

		blue = m_imageArray[i];
		green = m_imageArray[i+1];
		red = m_imageArray[i+2];
		
		m_realColorImageArray[k] = blue;
		m_realColorImageArray[k+1] = green;
		m_realColorImageArray[k+2] = red;

		gray = (BYTE)(0.3*red+0.59*green+0.11*blue);

		m_imageArray[i] = gray;
		m_imageArray[i+1] = gray;
		m_imageArray[i+2] = gray;

		m_realImageArray[j] = m_imageArray[i];

		i += 3;
		k += 3;
		j++;

		////跳过填充字节
		if (j % m_width == 0)
		{
			i += m_addByte;
		}
		
	}
	
	return 1;
}


2.图像转换为ASNII码文件

三个步骤:(1)提取图像数据(2)建立映射表(3)处理灰度并映射

映射表我建立的是8个字符'@','$','#','%','!','~','^','`'

把灰度值除上32将其范围映射到0-7这个范围内。

将灰度值按照映射表映射。

/******************************************
 *对图像的每个像素做文本映射,最终写入文件*
 ******************************************/
int CBitMapFile::turn2Txt(CFile& txtFile)
{
	char* _txtBuf = new char[m_width*m_height+2*m_height];
	memset(_txtBuf,0,m_width*m_height+2*m_height);

	//文本映射
	char txtMap[8] = {'@','$','#','%','!','~','^','`'};

	char* _buf = new char[m_width+2];
	memset(_buf,0,m_width+2);
	//TRACE(_T("\'\\r\'=%x,\'\\n\'=%x"),'\r','\n');
	for (int i = m_height-1;i>=0;i--)
	{
		for (int j = 0;j<m_width;j++)
		{
			_buf[j] = txtMap[m_realImageArray[i*m_width+j]>>5];
			
		}
		
		_buf[m_width] = '\r';
		_buf[m_width+1] = '\n';
		
		for (int k=0;k<m_width+2;k++)
		{
			_txtBuf[(m_height-1-i)*m_width+k+(m_height-1-i)*2] = _buf[k];
		
		}
	}
	
	txtFile.Write(_txtBuf,sizeof(char)*(m_width*m_height+2*m_height));

	delete _txtBuf;
	delete _buf;
	return 1;
}

3.直方图均衡化

每一幅图像都有自己的直方图


图像取自冈萨雷斯的《数字图像处理》第三版

这幅图像的灰度大部分集中在较高的灰度,均衡化就使图像在概率率较大的地方稀疏一点,概率较小的地方稠密一点。

方法是:(1)统计各个灰度的概率(2)归一化(3)画直方图(4)累计概率(5)取整得到映射(6)将原灰度值映射到新灰度值

/********************************************
 *	对bmp文件的每个像素的灰度值进行统计		*
 ********************************************/
int CBitMapFile::addupLevel()
{
	for (int i = 0;i<m_width*m_height;i++)
	{
		m_grayStatistic[m_realImageArray[i]] += 1;
		
	}
	for (int i = 0;i<256;i++)
	{
		if (m_grayStatistic[i]>m_max)
		{
			m_max = m_grayStatistic[i];
		}
	
	}
	//TRACE(_T("m_max = %d\n"),m_max);
	return 1;
}
/********************************************
 *	对bmp文件的每个像素的灰度值进行归一化	*
 *		并计算每个像素灰度值的概率			*
 ********************************************/
int CBitMapFile::turn2One()
{
	for (int i =0;i<256;i++)
	{
		m_grayTurn2OneData[i] = (double)m_grayStatistic[i]/m_max;
		m_grayFrequencyPerLevel[i] = (double)m_grayStatistic[i]/(m_width*m_height);
	
	}
	m_maxFrequency = m_max/(m_width*m_height);
	return 1;
}

/********************************************
 *	清除统计数组、归一化数组、频率数组		*
 ********************************************/
void CBitMapFile::clearup()
{
	memset(m_grayStatistic,0,sizeof(LONG)*256);
	memset(m_grayTurn2OneData,0,sizeof(double)*256);
	memset(m_grayFrequencyPerLevel,0,sizeof(double)*256);
	m_max = 0;
	m_maxFrequency = 0.0f;
}
/********************************************
 *				灰度均衡化					*
 ********************************************/
void CBitMapFile::equation(CFile& file)
{
	double _temp =0.0f;
	double* _array = new double[256];
	memset(_array,0,sizeof(double)*256);
	int* _intArray = new int[256];
	memset(_intArray,0,sizeof(int)*256);
	BYTE* _writeArray = new BYTE[m_sizeImage];
	memset(_writeArray,0,sizeof(BYTE)*m_sizeImage);
	for(int i = 0;i<256;i++)
	{
		_array[i] = ((m_grayFrequencyPerLevel[i])*255)+_temp;
		_temp = _array[i];
		
	}
	for (int i = 0;i<256;i++)
	{
		_intArray[i] = (int)(_array[i]);
	}
	for (int i = 0,j = 0;i<m_sizeImage;)
	{
		
		_writeArray[i] = _intArray[m_realImageArray[j]];
		_writeArray[i+1] = _intArray[m_realImageArray[j]];
		_writeArray[i+2] = _intArray[m_realImageArray[j]];
		j++;
		i += 3;
		if (j%m_width == 0)
		{
			for (int k = 0;k<m_addByte;k++)
			{
				_writeArray[i+k] = 0;
				
			}
			i += m_addByte;
		}
	}
	file.Write(&m_file_header,sizeof(BITMAPFILEHEADER));
	file.Write(&m_info_header,sizeof(BITMAPINFOHEADER));
	file.Write(_writeArray,sizeof(BYTE)*m_sizeImage);
	delete _array;
	delete _intArray;
	delete _writeArray;
}


4.伽马校正

伽马校正其实很简单,就是将旧的灰度值通过一个由灰度值为底,伽马次幂的映射得到新的灰度值,它的做用是,对于不同的伽马系数的选取,会使得某些较亮的图片,变得对比度适当。

/********************************************
 *				伽马校正					*
 ********************************************/
void CBitMapFile::gammaCorrection(double gamma,CFile& file)
{
	//数据准备
	double* _correctData = new double[m_width*m_height];
	BYTE* _writeArray = new BYTE[m_sizeImage];
	memset(_writeArray,0,sizeof(BYTE)*m_sizeImage);
	memset(_correctData,0,sizeof(double)*m_width*m_height);
	//算法
	for (int i = 0;i<m_width*m_height;i++)
	{
		_correctData[i] = (double)m_realImageArray[i]/255;
	
		_correctData[i] = pow(_correctData[i],gamma)*255;

	}
	//写入文件准备
	for (int i = 0,j = 0;i<m_sizeImage;)
	{
		_writeArray[i] = (BYTE)_correctData[j];
		_writeArray[i+1] = (BYTE)_correctData[j];
		_writeArray[i+2] = (BYTE)_correctData[j];
		j++;
		i += 3;
		if (j%m_width == 0)
		{
			for (int k = 0;k<m_addByte;k++)
			{
				_writeArray[i+k] = 0;
				
			}
			i += m_addByte;
		}
	}
	//写入文件
	file.Write(&m_file_header,sizeof(BITMAPFILEHEADER));
	file.Write(&m_info_header,sizeof(BITMAPINFOHEADER));
	file.Write(_writeArray,sizeof(BYTE)*m_sizeImage);
	
	delete _writeArray;
	delete _correctData;
}


这个是伽马选择7.5的效果

4.哈尔小波变换(HWT,haar wavelet tansform)

这个是小波变换里最简单的一个,由于涉及较多的数学,这里就不做赘述了,只是附上程序。(程序使用的矩阵乘法是我自己写的,效率较低,经过测试在128*128的大小的图像效果可以,再大就会出现未响应的现象。)

注意,哈尔小波变换的矩阵是偶数*偶数的,所以图片的行列也必须是偶数。

Matrix.h

#pragma once
#define ZERO 0	//零阵
#define IDENTITY 1//单位阵
#define HAAR 2//HAAR小波矩阵
#define UNSQUARE -1//非方阵
#define UNSAME -2//非同型矩阵
#define UNSAME -2//非同型矩阵
#define UNEVEN -3//行列非偶数

class CMatrix
{
public:
	CMatrix(int r,int c);
	CMatrix(CMatrix& m);
	CMatrix(double* d,int r,int c);
	CMatrix(BYTE* d,int r,int c);
	~CMatrix();
	int inital(int type);//初始化为单位阵,或特殊矩阵(以后扩展)
#ifdef _DEBUG
	void display();
#endif
	//////////////////////////////////////////////////////////////////////////
public:
	CMatrix& transpose();//矩阵的转置
	void nonZero();
	//////////////////////////////////////////////////////////////////////////
public:
	 CMatrix& operator=(CMatrix& m1);
	 friend CMatrix operator+(CMatrix& m1,CMatrix& m2);
	 friend CMatrix operator-(CMatrix& m1,CMatrix& m2);
	 friend CMatrix operator*(CMatrix& m1,double& a);
	 friend CMatrix operator*(CMatrix& m1,CMatrix& m2);
	//////////////////////////////////////////////////////////////////////////
public:
	inline int getRow(){return m_row;}
	inline int getCol(){return m_col;}
	//inline CString getName(){return m_name;}
	inline double getElem(int r,int c){return m_data[r*m_row+c];}
	inline double* getData(){return m_data;}
	//////////////////////////////////////////////////////////////////////////
protected:
	int m_row;
	int m_col;
	double* m_data;
//	CString m_name;
};


Matrix.cpp

#include "StdAfx.h"

#include "MatrixBase.h"
#ifdef _DEBUG
#include <iostream>
#endif

CMatrix::CMatrix(int r,int c)
{
	m_row = r;
	m_col = c;
	m_data = new double[r*c];
	memset(m_data,0,sizeof(double)*r*c);
}
CMatrix::CMatrix(double* d,int r,int c)
{
	m_row = r;
	m_col = c;
	m_data = new double[r*c];
	for (int i = 0;i<r*c;i++)
	{
		m_data[i] = d[i];
	}
}
CMatrix::CMatrix(BYTE* d,int r,int c)
{
	m_row = r;
	m_col = c;
	m_data = new double[r*c];
	for (int i = 0;i<r*c;i++)
	{
		m_data[i] = (double)d[i];
	}
}
CMatrix::CMatrix(CMatrix& m)
{
	this->m_row = m.m_row;
	this->m_col = m.m_col;
	m_data = new double[m_row*m_col];
	for (int i = 0;i<m_row*m_col;i++)
	{
		this->m_data[i] = m.m_data[i];
		TRACE(_T("data[%d]=%f\n"),i,this->m_data[i]);
	}
}
CMatrix::~CMatrix()
{
	delete[] m_data;
}
int CMatrix::inital(int type)
{
	
	switch(type)
	{
	case IDENTITY:
		if (m_row != m_col)
		{
			return UNSQUARE;
		}
		for (int i=0;i<m_col;i++)
		{
			m_data[i*m_row+i] = 1;
		}
		break;
	case HAAR:
		if (m_row != m_col)
		{
			return UNSQUARE;
		}
		if (m_row%2 != 0)
		{
			return UNEVEN;
		}
		for(int i = 0;i<m_row/2;i++)
		{
			m_data[i*m_row+i*2] = 1;
			m_data[i*m_row+i*2+1] = 1;
		}
		for (int i = m_row/2,j = 0;i<m_row;i++,j++)
		{
			m_data[i*m_row+j*2] = -1;
			m_data[i*m_row+j*2+1] = 1;
		}
		break;
	default:
		break;
	}
	return type;
}
CMatrix& CMatrix::operator=(CMatrix& m1)
{
	ASSERT(m_row == m1.getRow() && m_col == m1.getCol());
	for (int i = 0;i<m_row*m_col;i++)
	{
		m_data[i] = m1.getElem(i/m_row,i%m_row);
		TRACE(_T("\'=\'data[%d]=%f\n"),i,m_data[i]);
	}
	return *this;
}
CMatrix operator+(CMatrix& m1,CMatrix& m2)
{
	ASSERT(m1.m_row == m2.m_row && m1.m_col==m2.m_col);
	CMatrix ret(m1.m_row,m1.m_col);
	for (int i = 0;i<m1.m_row*m1.m_col;i++)
	{
		ret.m_data[i] = m1.m_data[i]+m2.m_data[i];
		TRACE(_T("ret[%d]=%f\n"),i,ret.m_data[i]);
	}
	return ret;

}
CMatrix operator-(CMatrix& m1,CMatrix& m2)
{
	ASSERT(m1.m_row == m2.m_row && m1.m_col==m2.m_col);
	CMatrix ret(m1.m_row,m1.m_col);
	for (int i = 0;i<m1.m_row*m1.m_col;i++)
	{
		ret.m_data[i] = m1.m_data[i]-m2.m_data[i];
		TRACE(_T("ret[%d]=%f\n"),i,ret.m_data[i]);
	}
	return ret;
}
CMatrix operator*(CMatrix& m1,double& a)
{
	CMatrix ret(m1);
	for (int i = 0;i<m1.m_row*m1.m_col;i++)
	{
		ret.m_data[i] *=a;
		TRACE(_T("ret[%d]=%f\n"),i,ret.m_data[i]);
	}
	return ret;
}
CMatrix operator*(CMatrix& m1,CMatrix& m2)
{
	ASSERT(m1.m_col == m2.m_row);
	CMatrix ret(m1.m_row,m2.m_col);
	for (int i= 0;i<m1.m_row;i++)
	{
		for (int j = 0;j<m2.m_col;j++)
		{
			double _temp = 0;
			for (int k = 0;k<m1.m_col;k++)
			{
				_temp += m1.m_data[i*m1.m_row+k]*m2.m_data[k*m2.m_row+j];
			}
			ret.m_data[i*m1.m_row+j] = _temp;
		}
	}
	return ret;
}
CMatrix& CMatrix::transpose()
{
	double* _newData = new double[m_row*m_col];
	
	for (int i = 0;i<m_row;i++)
	{
		for (int j=0;j<m_col;j++)
		{
			_newData[j*m_col+i] = m_data[i*m_row+j];
		}
	}
	delete m_data;
	m_data = _newData;
		
	return *this;
	
}
void CMatrix::nonZero()
{
	for (int i = 0;i<m_row;i++)
	{
		for (int j = 0;j<m_col;j++)
		{
			if(m_data[i*m_row+j]<0)
			{
				m_data[i*m_row+j]=0;
			}
		}
	}
}
#ifdef _DEBUG
void CMatrix::display()
{
	std::cout<<"[\n";
	for (int i = 0;i<m_row*m_col;i++)
	{
		std::cout<<m_data[i]<<" ,";
		if ((i+1)%m_row == 0)
		{
			std::cout<<std::endl;
		}
	}
	std::cout<<"]"<<std::endl;
}
#endif


哈尔小波变换函数

/********************************************
 *				HAAR小波变换				*
 ********************************************/
void CBitMapFile::haarTransform(CFile& file)
{
	CMatrix imageMatrix(m_realImageArray,m_height,m_width);
	CMatrix haarMatrix_r(m_height,m_height);
	CMatrix haarMatrix_c(m_width,m_width);
#ifdef _DEBUG
	imageMatrix.display();
#endif
	haarMatrix_c.inital(HAAR);
	haarMatrix_c = haarMatrix_c.transpose();
	haarMatrix_r.inital(HAAR);
	imageMatrix = haarMatrix_r*imageMatrix;
	double _d = 0.25*sqrt(2.0);
	imageMatrix = imageMatrix*_d;
	imageMatrix = imageMatrix*haarMatrix_c;
	imageMatrix = imageMatrix*_d;
	

	imageMatrix.nonZero();
#ifdef _DEBUG
	imageMatrix.display();
#endif	
	
	double* _correctData = imageMatrix.getData();
	BYTE* _writeArray = new BYTE[m_sizeImage];
	memset(_writeArray,0,sizeof(BYTE)*m_sizeImage);

	for (int i = 0,j = 0;i<m_sizeImage;)
	{
		_writeArray[i] = (BYTE)_correctData[j];
		_writeArray[i+1] = (BYTE)_correctData[j];
		_writeArray[i+2] = (BYTE)_correctData[j];
		j++;
		i += 3;
		if (j%m_width == 0)
		{
			for (int k = 0;k<m_addByte;k++)
			{
				_writeArray[i+k] = 0;

			}
			i += m_addByte;
		}
	}
	file.Write(&m_file_header,sizeof(BITMAPFILEHEADER));
	file.Write(&m_info_header,sizeof(BITMAPINFOHEADER));
	file.Write(_writeArray,sizeof(BYTE)*m_sizeImage);

	delete _writeArray;
	//delete _correctData;
}


处理后图像

由于bmp格式是倒着存储图像数据的,因为个人时间原因没有将其倒回,所以出现这种现象。

实验软件可以在这里下载:http://download.csdn.net/detail/smells2/4162515

 

2018-03-26 17:06:07 Julialove102123 阅读数 5317

均值滤波

均值滤波,是图像处理中最常用的手段,从频率域观点来看均值滤波是一种低通滤波器,高频信号将会去掉,因此可以帮助消除图像尖锐噪声,实现图像平滑,模糊等功能。理想的均值滤波是用每个像素和它周围像素计算出来的平均值替换图像中每个像素。采样Kernel数据通常是3X3的矩阵,如下表示:

从左到右从上到下计算图像中的每个像素,最终得到处理后的图像。均值滤波可以加上两个参数,即迭代次数,Kernel数据大小。一个相同的Kernel,但是多次迭代就会效果越来越好。同样,迭代次数相同,Kernel矩阵越大,均值滤波的效果就越明显。


中值滤波

中值滤波也是消除图像噪声最常见的手段之一,特别是消除椒盐噪声,中值滤波的效果要比均值滤波更好。中值滤波是跟均值滤波唯一不同是,不是用均值来替换中心每个像素,而是将周围像素和中心像素排序以后,取中值,一个3X3大小的中值滤波如下:

 


最大最小值滤波

最大最小值滤波是一种比较保守的图像处理手段,与中值滤波类似,首先要排序周围像素和中心像素值,然后将中心像素值与最小和最大像素值比较,如果比最小值小,则替换中心像素为最小值,如果中心像素比最大值大,则替换中心像素为最大值。一个Kernel矩阵为3X3的最大最小值滤波如下:

 


双边滤波

一种同时考虑了像素空间差异与强度差异的滤波器,因此具有保持图像边缘的特性。

先看看高斯滤波器


其中W是权重,i和j是像素索引,K是归一化常量。公式中可以看出,权重只和像素之间的空间距离有关系,无论图像的内容是什么,都有相同的滤波效果。

再来看看双边滤波器,它只是在原有高斯函数的基础上加了一项,如下


其中 I 是像素的强度值,所以在强度差距大的地方(边缘),权重会减小,滤波效应也就变小。总体而言,在像素强度变换不大的区域,双边滤波有类似于高斯滤波的效果,而在图像边缘等强度梯度较大的地方,可以保持梯度


引导滤波

与双边滤波最大的相似之处,就是同样具有保持边缘特性。在引导滤波的定义中,用到了局部线性模型,至于该模型,可以暂时用下图简单的理解


该模型认为,某函数上一点与其邻近部分的点成线性关系,一个复杂的函数就可以用很多局部的线性函数来表示,当需要求该函数上某一点的值时,只需计算所有包含该点的线性函数的值并做平均即可。这种模型,在表示非解析函数上,非常有用。

同理,我们可以认为图像是一个二维函数,而且没法写出解析表达式,因此我们假设该函数的输出与输入在一个二维窗口内满足线性关系,如下


其中,q是输出像素的值,I是输入图像的值,i和k是像素索引,a和b是当窗口中心位于k时该线性函数的系数。其实,输入图像不一定是待滤波的图像本身,也可以是其他图像即引导图像,这也是为何称为引导滤波的原因。对上式两边取梯度,可以得到


即当输入图像I有梯度时,输出q也有类似的梯度,现在可以解释为什么引导滤波有边缘保持特性了。

下一步是求出线性函数的系数,也就是线性回归,即希望拟合函数的输出值与真实值p之间的差距最小,也就是让下式最小


这里p只能是待滤波图像,并不像I那样可以是其他图像。同时,a之前的系数(以后都写为e)用于防止求得的a过大,也是调节滤波器滤波效果的重要参数。通过最小二乘法,我们可以得到


其中,是I在窗口w_k中的平均值,是I在窗口w_k中的方差,是窗口w_k中像素的数量,是待滤波图像p在窗口w_k中的均值。

在计算每个窗口的线性系数时,我们可以发现一个像素会被多个窗口包含,也就是说,每个像素都由多个线性函数所描述。因此,如之前所说,要具体求某一点的输出值时,只需将所有包含该点的线性函数值平均即可,如下


这里,w_k是所有包含像素i的窗口,k是其中心位置。

当把引导滤波用作边缘保持滤波器时,往往有 I = p ,如果e=0,显然a=1, b=0是E(a,b)为最小值的解,从上式可以看出,这时的滤波器没有任何作用,将输入原封不动的输出。如果e>0,在像素强度变化小的区域(或单色区域),有a近似于(或等于)0,而b近似于(或等于),即做了一个加权均值滤波;而在变化大的区域,a近似于1,b近似于0,对图像的滤波效果很弱,有助于保持边缘。而e的作用就是界定什么是变化大,什么是变化小。在窗口大小不变的情况下,随着e的增大,滤波效果越明显。

在滤波效果上,引导滤波和双边滤波差不多,在一些细节上,引导滤波较好。引导滤波最大的优势在于,可以写出时间复杂度与窗口大小无关的算法,因此在使用大窗口处理图片时,其效率更高。


def guidedfilter(I,p,r,eps):
    '''I:引导图图;
    p:输入图(p=I);
    r :半径:
    eps:regulation 
    f:为窗口半径为r的均值滤波器;
    corr:相关;
    var:方差;
    cov:协方差
    '''
    height,width = I.reshape()
    m_I = cv2.boxFilter(I,-1,(r,r))  #f_mean(I) 均值滤波blur和盒式滤波一样
    m_p = cv2.boxFilter(p,-1,(r,r))  #f_mean(p)


    m_II = cv2.boxFilter(I*I,-1,(r,r)) #f_mean(I.*I)
    m_Ip = cv2.boxFilter(I * p, -1, (r, r))  #f_mean(I.*p)

    var_I = m_II-m_I*m_I   #求方差:corr_I -mean_I.*mean_I
    cov_Ip = m_Ip - m_I * m_p  #协方差: #cov_Ip-mean_I.*mean_p

    a = cov_Ip/(var_I+eps)  #cov_Ip./(var_I+eps)
    b = m_p-a*m_I   #mean_p -a.*mean_I
    m_a = cv2.boxFilter(a,-1,(r,r))  #mean_a
    m_b = cv2.boxFilter(b,-1,(r,r))  #mean_b
    return m_a*I+m_b

2019-06-28 09:58:26 AugustMe 阅读数 853

深度学习模型训练时通常都需要大量的训练集,我们在做图像相关的应用时同样需要进行图像数据增加,下面我将给大家总结10种图像数据增强常用的方式

1、水平翻转
随机的对图片进行水平翻转,这个参数适用于水平翻转不影响图片语义的时候。

2、竖直翻转
随机的对图片进行竖直翻转,这个参数适用于竖直翻转不影响图片语义的时候。

3、随机翻转角度
设置一个0~180的度数,用来指定随机旋转图片的角度。

4、随机水平平移
用来指定水平方向随机移动的程度。

5、随机竖直平移
用来指定竖直方向随机移动的程度。

6、随机错切变换
在某方向上,按照一定的比例对图形的每个点到某条平行于该方向的直线的有向距离做放缩得到的平面图形。

7、随机放大
对图片进行随机的放大。

8、颜色抖动
改变图片的颜色,通过对颜色通道的数值偏移,改变图片的整体的颜色。

9、rescale
rescale的作用是对图片的每个像素值均乘上这个放缩因子,这个操作在所有其它变换操作之前执行,在一些模型当中,直接输入原图的像素值可能会落入激活函数的饱和区,因此设置放缩因子为1/255,把像素值放缩到0和1之间有利于模型的收敛,避免神经元饱和。图片经过rescale之后,保存到本地的图片用肉眼看是没有任何区别的。

10、fill_mode
fill_mode为填充模式,如前面提到,当对图片进行平移、放缩、错切等操作时,图片中会出现一些缺失的地方,就由fill_mode中的参数确定。包括:“constant”、“nearest”(默认)、“reflect”和“wrap”。

通常来说我们不会只使用单一的数据增加方法,而是会多种方式结合使用

以上只是常用的几种图像数据增强方法,还有更好的其他方法,请结合自身项目。

引用:
https://mp.weixin.qq.com/s?__biz=MzUxOTgxMjkwNA==&mid=2247485619&idx=1&sn=d3a30397462861bf8b01c2570e9b8388&chksm=f9f2aaf4ce8523e25b7691bdb2e2e0526580f4c14ca307089017f21a3ff82232857039ac319d&mpshare=1&scene=1&srcid=11238ugMfOHeYBHXLTfT0llT&key=fe048f5ad4fa1bcf827d20099e0f30a24b151eaee46d0b492d027be2f0e420506744d70e6e8e97982b4cf9efdde30378cf048d45208189d545c91723f9cd1bd9a8a48a13e0a20c1a5bf72644e2bb575c&ascene=1&uin=MjE3OTYwMjg2Mw%3D%3D&devicetype=Windows+10&version=62060833&lang=zh_CN&pass_ticket=apm0Olp6oFmGwJatwtCpRNrEa36m9QcJSdkodK2aDwPRHUFGGRA79xznbiIxDOjZ

2018-05-02 22:31:27 fanyun_01 阅读数 17529

      1.OpenCV,主要以算法形式,展示其实现;也就是说,它实际提供的是各种图像处理算法。若需具体应用,需要组合其算法以实现某个功能。

                                          

OpenCV 的全称 Open Source Computer Vision Library,是一个基于BSD许可(开源)发行的跨平台计算机视觉库,又名 “开源计算机视觉库”。OpenCV 是一个开源发行的跨平台计算机视觉库,可运行在 Windows、Android、Maemo、FreeBSD、OpenBSD、iOS、Linux 和 Mac OS 等平台。使用者可在 SourceForge 获得官方版本, 或从 SVN 获得开发版本。OpenCV 也用 CMake。

在 Windows 上编译 OpenCV 中与摄像输入有关部分时,需要 DirectShow SDK 中的一些基类。该 SDK 可从预先编译的 Microsoft Platform SDK (or DirectX SDK 8.0 to 9.0c / DirectX Media SDK prior to 6.0) 的子目录 Samples\Multimedia\DirectShow\BaseClasses 获得。

OpenCV 轻量且高效 —— 由一系列 C 函数和少量 C++ 类构成,同时提供了 Python、Ruby、MATLAB 等语言接口,实现了图像处理和计算机视觉方面的很多通用算法。

OpenCV 用 C++ 语言编写,它的主要接口也是 C++ 语言,但依然保留了大量的 C 语言接口。OpenCV 库也有 Python、Java、MATLAB/OCTAVE (版本 2.5) 接口。这些语言的 API 接口函数,可通过在线文档获得。如今,OpenCV 也提供对于 C#、Ch、Ruby 的支持。

OpenCV 所有新开发和算法都采用 C++ 接口。

OpenCV 拥有包括 500 多个 C 函数的跨平台中、高层 API。OpenCV 不依赖于其它的外部库 —— 尽管也可使用某些外部库。

1999 年 Intel 开始建立 OpenCV,如今由 Willow Garage 提供支持。

OpenCV 为 Intel ® Integrated Performance Primitives (IPP) 提供了透明接口。这意味着,如果有为特定处理器优化的 IPP 库, OpenCV 将在运行时自动加载这些库。OpenCV 2.0 版代码已显著优化,无需 IPP 来提升性能,故 2.0 版不再提供 IPP 接口。

2010 年 9 月实现 CUDA 的 GPU 接口。

2015 年 6 月 4 日发布 OpenCV 3.0。

2016年12月,发布OpenCV 3.2版(合并969个修补程序,关闭478个问题)。

2017年8月3日,发布OpenCV 3.3版(最重要的更新是把DNN模块从contrib里面提到主仓库)。

2017年12月23日发布,最新版本是3.4 。

       2.imageMagic主要以应用形式,展示其实现,;譬如:图像切割、图像融合、图像模糊、图像锐化等。

                                           

ImageMagick 是一个免费开源、用于编辑、创建、合成图像的工具。ImageMagick 可读取、转换、写入多种格式图像。包括:图像切割、颜色替换、各种效果的应用,图像旋转、组合、文本、直线、多边形、椭圆、曲线、附加到图像伸展旋转、等等。

ImageMagick 遵守 GPL 许可协议,是一个免费工具:完全开放源码,可自由使用、复制、修改、发布;它可运行于大多数操作系统。ImageMagick 几乎可在任何非专有操作系统上编译,无论是 32 位还是 64 位 CPU,包括:Linux、Windows 95/98/ME/NT 4.0/2000/XP、Windows 2003、Windows 7、Windows 8、Macintosh (MacOS 9 /10)、VMS 和 OS/2。ImageMagick 的大多数功能的用法都是使用命令行。

ImageMagick 是一套功能强大、稳定且开源的工具集、开发包。可用来读、写和处理超过 200 多种格式的图片文件,包括流行的 TIF、JPG、JPEG、GIF、 PNG、PDF 以及 PhotoCD 等格式。

ImageMagick 可根据 Web 应用程序的需要动态生成图片, 可对一个(或一组)图片进行缩放、旋转、锐化、减色或增加特效等操作,并将操作结果以相同格式或其它格式保存;对图片的操作,即可通过命令行进行,也可通过 C/C++、Perl、Java、PHP、Python 或 Ruby 编程完成。同时 ImageMagick 还提供了一个高质量的 2D 工具包,部分支持 SVG。ImageMagick 的主要精力集中在性能,减少 Bug 以及提供稳定的 API 和 ABI 上。

                                 

       3.GraphicsMagick号称图像处理领域的瑞士军刀。其短小精悍的代码却提供了一个鲁棒、高效的工具和库集合,来处理图像的读取、写入和操作。

                                            

GraphicsMagick 号称图像处理领域的瑞士军刀。GraphicsMagick 短小精悍的代码,却提供了一个鲁棒、高效的工具和库集合,来处理图像的读取、写入和操作。

GraphicsMagick 支持大图片的处理,且做过 GB 级的图像处理实验。GraphicsMagick 能动态生成图片,特别适于互联网应用。

GaphicsMagick 不仅支持命令行模式,同时也支持 C、C++、Perl、PHP、Tcl、 Ruby、Lua、Python、Windows .NET、Windows COM 编程接口等的调用。事实上,GraphicsMagick 是从 ImageMagick 5.5.2 分支出来的,现在它已变得更稳定和更优秀,相比之下。

GraphicsMagick 可用来处理调整图片尺寸、旋转、加亮、颜色调整、增加特效等。GraphicsMagick 支持超过 88 种图像格式,包括重要的 DPX、GIF、JPEG、JPEG-2000、PNG、PDF、PNM 和 TIFF。通过使用 OpenMP 可利用多线程进行图片处理,增强了通过扩展 CPU 提高处理能力。

GraphicsMagick 可在绝大多数平台上使用,包括 Linux、Mac OS、Windows (2000、XP、Vista、7、8.X、10) 操作系统。

三种库的优势对比:

OpenCV 比较 ImageMagick:

(1).OpenCV 和 ImageMagick 代码都开源,方便开发;

(2).ImageMagick 最近更新不多,OpenCV 近几年有 Intel 的支持更新比较及时,功能越来越强大,bug 修复也比较及时;

(3).ImageMagick 使用简便;OpenCV 的使用稍微复杂,对使用者有一定的图像技术要求;

(4).ImageMagick 封装较好,使用灵活度稍低;OpenCV 使用比较灵活;

(5).ImageMagick 功能实现较少,主要是一些常用的图像处理,很多比较复杂的图像处理并没有实现。OpenCV 的算法实现非常强大,且从其最近版本更新的速度来看,它更加强大,很多经典的图像处理算法都有实现。作为一个图像开发者,这是一个很大的诱惑。

(6).ImageMagick 函数运行较慢, OpenCV 运行速度较快。常见函数 ,包括:图像读、图像压缩、图像写等 ,OpenCV 都要比 ImageMagick 快很多。

(7).OpenCV 不能解析 gif 文件格式,版权原因,试图载入 gif 文件会出错。若要用 OpenCV 功能,又需解析 gif 文件格式,可先用其他函数库将其读入再转化为 IplImage。ImageMagick 支持处理 gif 文件格式。

(8).ImageMagick 有一个不错的 sharpen 函数,用于锐化图像,效果挺不错。OpenCV 中没有锐化函数,没有相应的锐化算法实现。若确想使用这个函数,可在 OpenCV 下实现 ImageMagick 相应源代码。

OpenCV 功能强大,代码运行速度快,更新速度也快,但对开发者有一定的要求。ImageMagick 使用比较简单,对图像处理不太熟悉,又只想实现简单图像处理时,可选择。

若选择使用 ImageMagick,建议使用 GraphicsMagick。GraphicsMagick 和 ImageMagick 的函数调用方法相同,但 GraphicsMagick 在效率上优于 ImageMagick,特别是在 windows 下运行。

GraphicsMagick 比较 ImageMagick:

(1).GraphicsMagick 更有效率,能更快的完成处理工作;

(2).GraphicsMagick 更小更容易安装;

(3).GraphicsMagick 已被 Flickr (雅虎旗下图片分享网站) 和 Etsy (网络商店平台) 使用,每天处理百万计的图片;

(4).GraphicsMagick 和已安装软件不会发生冲突;

(5).GraphicsMagick 几乎没有安全问题;

(6).GraphicsMagick 的手册非常丰富;





几种常用的图像处理函数库

博文 来自: wujiahui1207
没有更多推荐了,返回首页