2018-09-22 14:32:35 lx_xin 阅读数 81

数字图像处理

数字图像基础

图像内插

用于图像放大、缩小、旋转、几何校正等任务。首先确定变换前后的坐标对应关系,用src表示转换前的图像尺寸,dst表示转换后的图像尺寸,src’表示转换后图像对应于原图像的坐标。对于图像缩放,缩放系数t=src/dstt=src/dst,则dst对应在src中的坐标为src=dsttsrc'=dst*t。考虑到转换后图像未处在原图像中间的情况,将公式修正为src=(dst+0.5)t0.5src'=(dst+0.5)*t-0.5。对于旋转、矫正等使用相关公式计算src’后使用以下内插方法进行像素赋值。

修正前
修正后
  1. 最近邻内插
    将距离src’最近的src像素赋值给src’。
  2. 双线性内插
    利用src’最近的2*2个src像素确定赋值大小。
根据图中定义,先对X再对Y插值,P点的插值结果为

插值公式
插值公式
其中各式分母均为1。
参考资料:三十分钟理解:线性插值,双线性插值Bilinear Interpolation算法

  1. 双三次插值
    利用src’最近的4×44\times4个src像素值确定赋值大小。计算每个像素值到src’的距离,根据分段函数(这里选用BiCubic基函数)确定像素值的权值,对4×44\times4个像素值进行加权求和得到src’。
    BiCubic基函数
    例如对于点src’(1.5,1.5),距离最近的4*4坐标为(0,0),(0,1)···(3,3),对于点(0,0),X方向距离为1.5,Y方向距离为1.5,根据BiCubic基函数得到对应的权值w(0,0)xw_{(0,0)}^{x}(这里上标表示坐标方向不是乘方)和w(0,0)yw_{(0,0)}^{y},则(0,0)点对于src’的贡献为该点处的灰度值i×w(0,0)x×w(0,0)yi\times w_{(0,0)}^{x} \times w_{(0,0)}^{y}。依次求得各点的贡献值后求和得到最终的src’。
    参考资料:图像缩放之双三次插值法
  2. Lanczos插值(兰索斯插值)
    基本思路与双三次插值类似,但是改变了基函数类型,并且使用的邻域范围不固定,可自由选择。Lanczos插值函数为:
    Lanczos
    插值公式为:
    插值公式
    其中a为参数大小,x,y为待带插值位置,i,j为当前采样位置。可以设置不同的参数大小得到不同的效果。a取2适合于缩小插值,3适合于放大插值。在opencv中默认取4。
    参考资料:Lanczos插值滤波器
    几种插值算法对比研究
    以上几种插值方法效果依次更好,但同时复杂度也依次提升。

像素距离度量

对于点A(x1,y1)与点B(x2,y2)有如下距离度量

  1. 欧氏距离
    De(A,B)=[(x1x2)2+(y1y2)2]12D_{e}(A,B)=[(x_{1}-x_{2})^{2}+(y_{1}-y_{2})^{2}]^{\frac{1}{2}}与A距离小于r的点在半径为r的圆内。
  2. 城区距离(曼哈顿距离)
    D4(A,B)=x1x2+y1y2D_{4}(A,B)=\left |x_{1}-x_{2} \right |+\left |y_{1}-y_{2} \right |与A距离小于r的点在半径为r的菱形内。
  3. 棋盘距离
    D8(A,B)=max(x1x2,y1y2)D_{8}(A,B)=max(\left |x_{1}-x_{2} \right |,\left |y_{1}-y_{2} \right |)与A距离小于r的点在半径为r的正方形内。

灰度变换与空间滤波

基本的灰度变换函数

  • 图像反转
    对于灰度级为L-1的图像,反转定义为dst=L1srcdst=L-1-src
  • 对数变换
    dst=clog(1+src)csrc0dst =c*\log (1+src),其中c为常数,src\geq 0。对数变换扩展低像素值,压缩高灰度值。对数变换的一个重要作用是压缩图像动态范围,例如傅里叶频谱的图像显示通常经过了对数变换。
  • 幂律(γ\gamma)变换
    dst=csrcγcγdst=c*src^{\gamma},其中c和\gamma为正常数。又叫做伽马校正,通常用于设备产生的伽马响应的校正。当γ<1\gamma<1时可以扩展灰度级,用于处理整体偏暗的图片;γ>1\gamma>1时可以压缩灰度级,用于处理整体偏亮的图片。
    321
  • 分段线性变换函数
    对比度拉伸:通过设定不同的变换函数拉伸特定灰度范围内的图像。
    分段线性变换函数
    灰度级分层:将特定范围内的灰度值设为给定值以突出特定灰度的图像。
    灰度级分层
    比特平面分层:将灰度值用2进制表示,如256灰度级图像可表示为8位二进制数,将每一个像素同位的二进制数组成一幅图像(该图像只包含0和1),可得到8幅图像,即原图像的比特平面分层。其中层数越高对原图像灰度值的决定性越。可以根据分层后的图像重建原图像,并且不一定要使用所有图像,例如只使用最高的4层重建图像得到的图像丢失信息较少,单可以减少一半的存储空间。

直方图处理

直方图:统计图像中每个灰度值包含的像素点个数,绘制横轴为0L10\sim L-1,纵轴为对应的像素点个数的柱状图称为直方图。将直方图纵轴除以图像总像素点数得到归一化直方图,反映每种灰度出现的概率。

  • 直方图均衡化
    输入图像s,求s的归一化直方图(由于灰度值为离散变量,可用数组表示为r[i]),再求其累计直方图s[i],则对于灰度i,转换公式为i’=(L-1)*s[i]。直方图均衡化的目的是为了扩展动态范围,使变换后的灰度概率接近均匀分布。例如:
项目 - - - - - -
原始灰度值 0 1 2 3 4 5
像素比例 0.3 0.4 0.2 0 0 0.1
累计比例 0.3 0.7 0.9 0.9 0.9 1
变换后灰度值=累计比例*最大灰度值 2(1.5) 4(3.5) 5(4.5) 5(4.5) 5(4.5) 5(5)
变换后比例 0 0 0.3 0 0.4 0.3
  • 直方图规范化(匹配)
    输入图像s和规定图像z,分别求s和z的直方图均衡化的灰度映射记为s->T(S)和z->T(z),令T(S)=T(z),则可建立s->T(s)=T(z)->z的映射关系。当T(z)->z的对应关系不唯一时,通常选择较小的作为映射结果。例如:
项目 - - - - - -
灰度值 0 1 2 3 4 5
输入像素比例 0.3 0.4 0.2 0 0 0.1
输入累计比例 0.3 0.7 0.9 0.9 0.9 1
变换后灰度值=累计比例*最大灰度值 2(1.5) 4(3.5) 5(4.5) 5(4.5) 5(4.5) 5
规定像素比例 0 0.1 0.1 0.2 0.1 0.5
规定累计比例 0 0.1 0.2 0.4 0.5 1
变换后灰度值=累计比例*最大灰度值 0 1(0.5) 1 2 3(2.5) 5(5)
变换后灰度值 3 4 5 5 5 5
变换后像素比例 0 0 0 0.3 0.4 0.3
  • 局部直方图处理
    可将直方图处理应用于图像局部,如3*3的邻域内。方法为在邻域内进行直方图统计,并求出灰度映射关系,用于对中心像素进行变换,并移动邻域位置进行全图处理。

平滑空间滤波器

  1. 平滑线性滤波器
    均值滤波器(也称为盒状滤波器):将邻域内各像素值均值作为中心像素的结果。
    加权均值滤波器:将邻域内各像素值的加权均值作为中心像素的结果。
  2. 统计排序(非线性)滤波器
    最大值滤波器:将邻域内各像素值的最大值作为中心像素的结果。
    最小值滤波器:将邻域内各像素值的最小值作为中心像素的结果。
    中值滤波器:将邻域内各像素值排序后的中值作为中心像素的结果。

锐化空间滤波器

  1. 一阶微分锐化图像——梯度
    Robert算子:
    Robert算子
    Sobel算子:
    Sobel算子
  2. 二阶微分锐化图像——拉普拉斯算子
    拉普拉斯算子
  3. 非锐化掩蔽和高提升滤波
    非锐化掩蔽:主要步骤为:a)模糊原图像;b)从原图中渐趋模糊图像得到模板;c)将模板叠加到原图上得到锐化图像。
    高提升滤波:在c)中叠加时在模板前加权重k,当k=1时得到非锐化掩蔽,k>1则为高提升滤波。

频率域滤波

待完善

图像复原与重建

图像退化、复原模型

用下式表示图像退化(线性、位置不变的):
g(x,y)=h(x,y)f(x,y)+η(x,y)g(x,y)=h(x,y)\bigstar f(x,y)+\eta (x,y)g为退化后图像,f为原图像,h为退化函数,η为噪声。★表示卷积运算。根据空间域中的卷积对于频率域中的乘积,频率域中退化表示为:
G(x,y)=H(x,y)F(x,y)+N(x,y)G(x,y)=H(x,y)F(x,y)+N(x,y)各项对应上式中的傅里叶变换。

噪声模型

待完善

只存在噪声的复原——空间滤波

通常滤波器尺寸为奇数,因为偶数滤波器无中心点。

  1. 均值滤波器
    算术均值滤波器f(x,y)=1mn(s,t)Sxyg(s,t)f(x,y)=\frac{1}{mn}\sum_{(s,t)\subset S_{xy}}^{ }g(s,t)
    Sxy为m*n的邻域。降低噪声同时模糊了原图。
    几何均值滤波器f(x,y)=[(s,t)Sxyg(s,t)]1mnf(x,y)=\left [\prod_{(s,t)\subset S_{xy}}^{ }g(s,t) \right ]^{\frac{1}{mn}}
    同样平滑图片,但较算术均值滤波器丢失的细节少。
    谐波均值滤波器f(x,y)=mn(s,t)Sxy1g(s,t)f(x,y)=\frac{mn}{\sum_{(s,t)\subset S_{xy}}^{ }\frac{1}{g(s,t)}}
    对于盐粒噪声及高斯噪声等效果较好,不适用于胡椒噪声。
    逆谐波均值滤波器f(x,y)=(s,t)Sxyg(s,t)Q+1(s,t)Sxyg(s,t)Qf(x,y)=\frac{\sum_{(s,t)\subset S_{xy}}^{ }g(s,t)^{Q+1}}{\sum_{(s,t)\subset S_{xy}}^{ }g(s,t)^{Q}}
    Q为滤波器的阶数。Q为正时消除胡椒噪声,Q为负时消除盐粒噪声,Q=0退化为算术均值滤波器,Q=-1为谐波均值滤波器。
  2. 统计排序滤波器
    中值滤波器f(x,y)=median(s,t)Sxyg(s,t)f(x,y)=\underset{(s,t)\subset S_{xy}}{median}{g(s,t)}
    比现行平滑滤波器引起的模糊少,处理单极或者双极脉冲效果较好。
    最大值和最小值滤波器f(x,y)=max(s,t)Sxyg(s,t)f(x,y)=\underset{(s,t)\subset S_{xy}}{max}{g(s,t)}
    f(x,y)=min(s,t)Sxyg(s,t)f(x,y)=\underset{(s,t)\subset S_{xy}}{min}{g(s,t)}
    用于发现图像中的最亮(暗)点,可以降低胡椒(盐粒)噪声。
    中点滤波器f(x,y)=12[max(s,t)Sxyg(s,t)+min(s,t)Sxyg(s,t)]f(x,y)=\frac{1}{2}\left [\underset{(s,t)\subset S_{xy}}{max}{g(s,t)}+\underset{(s,t)\subset S_{xy}}{min}{g(s,t)} \right ]结合了统计排序和求平均,适用于处理随机分布噪声如高斯噪声和均匀噪声。
    修正的阿尔法滤波器f(x,y)=1mnd(s,t)Sxygr(s,t)f(x,y)=\frac{1}{mn-d}\sum_{(s,t)\subset S_{xy}}^{ }g_{r}(s,t)
    其中gr(s,t)g_{r}(s,t)为去掉最大的d/2和最小的d/2个像素值后的邻域像素。当d=0,退化为算数均值滤波器;当d=mn-1时,退化为中值滤波器。在包括多种噪声时很有用,如混合有高斯噪声和椒盐噪声的情况。
  3. 自适应滤波器
    自适应局部降低噪声滤波器ση2\sigma _{\eta }^{2}为噪声方差,需要预先估计或者交互给出,σL2\sigma _{L }^{2}为图像局部方差,mLm_{L}为局部均值。基于以下准则构建滤波器a)当ση2\sigma _{\eta }^{2}为0,即无噪声,返回原始值;b)若局部方差与ση2\sigma _{\eta }^{2}高度相关,则返回g(x,y)的近似值;c)若两个方差相等,则返回邻域的算术均值。
    f(x,y)=g(x,y)ση2σL2[g(x,y)mL]f(x,y)=g(x,y)-\frac{\sigma _{\eta }^{2}}{\sigma _{L }^{2}}[g(x,y)-m_{L}]式中包含假设噪声方差不大于局部方差,若大于则设置比例为1。
    自适应中值滤波器:定义如下表示:
    zmin=Sxyzmax=Sxyz_{min}=S_{xy}中最小灰度值,z_{max}=S_{xy}中最大灰度值
    zmed=Sxyzxy=(x,y)z_{med}=S_{xy}中灰度中值,z_{xy}=坐标(x,y)处的灰度值
    Smax=SxyS_{max}=S_{xy}允许的最大尺寸
    则滤波器工作流程为:
    a)判断,若zmed>zmedz_{med}>z_{med}zmed<zmaxz_{med}<z_{max},转到b),否则增大窗口尺寸,重复a),当窗口尺寸>SmaxS_{max}输出zmedz_{med}
    b)若zxy>zminz_{xy}>z_{min}zxy<zmaxz_{xy}<z_{max},输出zxyz_{xy},否则输出zmedz_{med}
    该滤波先判断中值是否脉冲,若是则扩大搜索范围直到找到非脉冲的均值,若不是则判断当前点是否脉冲。若不是则输出当前点,否则输出中值。

线性、位置不变的退化

待补充

估计退化函数

  1. 图像观察估计
    选择信号较强的区域,可假设噪声影响较小。使用锐化等方式得到较清晰的图片作为原图像的估计,则用Hs(u,v)=Gs(u,v)Fs(u,v)H_{s}(u,v)=\frac{G_{s}(u,v)}{F_{s}(u,v)}作为退化函数的估计。
  2. 实验估计
    在采集设备可以得到的情况下,对冲激(小亮点)成像得到退化的冲激响应。冲击的傅里叶变换为常量,则退化函数的估计为H(u,v)=G(u,v)AH(u,v)=\frac{G(u,v)}{A}
  3. 建模估计
    基于特定专业知识建立退化模型,通常难度较大,但效果较好。

逆滤波

得到退化函数的估计H后可使用逆滤波复原图像。F^(u,v)=F(u,v)+N(u,v)H(u,v)\widehat F(u,v)={F}(u,v)+\frac{N(u,v)}{H(u,v)}当退化函数H较小时后一项会影响复原效果。因此可以限制滤波频率,减少遇到0值的概率。

最小均方误差(维纳)滤波

F^(u,v)=[1H(u,v)H(u,v)2H(u,v)2+K]G(u,v)\widehat F(u,v)=\left [\frac{1}{H(u,v)}\frac{\left |H(u,v) \right |^{2}}{\left |H(u,v) \right |^{2}+K} \right ]G(u,v)
其中H为退化函数,K为常数,通过交互选择确定。

约束最小二乘方滤波

待补充

几何均值滤波

待补充

彩色图像处理

待补充

形态学图像处理

基本操作定义

补集:AcA^{c}
腐蚀:AB={z(B)zA}A\ominus B =\left \{ z|(B)_{z} \subseteq A \right \}
膨胀:AB={z(B)zA}A\oplus B =\left \{ z|(B)_{z} \cap A\neq \varnothing \right \}
对偶性:(AB)c=AcB,(AB)c=AcB(A\ominus B)^{c}=A^{c}\oplus B,(A\oplus B)^{c}=A^{c}\ominus B
开操作:AB=(AB)BA\bullet B=(A\ominus B)\oplus B
开操作
闭操作:AB=(AB)BA\circ B=(A\oplus B)\ominus B
闭操作
击中击不中变换:AB=(AB1)(AB2)A\circledast B=(A\ominus B_{1})(A\oplus B_{2}),B1和B2分别为结构元的前景和背景部分。

基本形态学算法

边界提取:β(A)=A(AB)\beta (A)=A-(A\ominus B)
待补充

灰度级形态学

腐蚀:[fb](x,y)=min(s,t)bf(x+s,y+t)[f\ominus b](x,y)=\underset{(s,t)\in b}{min}f(x+s,y+t)
膨胀:[fb](x,y)=max(s,t)bf(xs,yt)[f\oplus b](x,y)=\underset{(s,t)\in b}{max}f(x-s,y-t)
开操作:fb=(fb)bf \circ b=(f \ominus b)\oplus b
闭操作:fb=(fb)bf \bullet b=(f\oplus b)\ominus b
开闭运算在这里插入图片描述
形态学平滑:顺序执行开闭操作。
形态学梯度:g=(fb)(fb)g=(f\oplus b)-(f\ominus b)
顶帽变换(白顶帽):That(f)=f(fb)T_{hat}(f)=f-(f\circ b),用于暗背景上的亮物体
底帽变换(黑底帽):Bhat(f)=(fb)bB_{hat}(f)=(f\bullet b)-b,用于亮背景上的按物体

图像分割

孤立点检测:拉普拉斯算子
线检测:
线检测模板
边缘模型:台阶模型、斜坡模型、屋顶模型
边缘模型
常用梯度算子:

  • Robert算子
    Robert算子
  • Prewitt算子
    Prewitt算子
    Prewitt算子
  • Sobel算子
     Sobel算子
    Sobel算子
  • Canny算子
    基本步骤:a)高斯滤波器平滑输入图像;b)计算梯度幅度图像和角度图像;c)将梯度根据方向规范化到八个方向,在梯度指向的方向应用非最大值抑制;d)用滞后阈值法处理和连接分析来检测边缘并连接边缘;e)根据实际需要进行细化操作。

霍夫变换
待补充

阈值处理

Otsu(大津法)
基本步骤:

  1. 计算输入图像的归一化直方图,用pi,i=0,1,2L1p_{i},i=0,1,2 \cdots L-1表示各个分量。
  2. 用公式P1(k)=i=0kpiP_{1}(k)=\sum_{i=0}^{k}p_{i},对于k=0~L-1计算累计和P1(k)P_{1}(k)
  3. 用公式m(k)=i=0kipim(k)=\sum_{i=0}^{k}i*p_{i},对于k=0~L-1计算累计均值m(k)m(k)
  4. 用公式mG=i=0L1ipim_{G}=\sum_{i=0}^{L-1}i*p_{i},计算全局灰度均值mGm_{G}
  5. 用公式σB2(k)=[mGP1(k)m(k)]2P1(k)[1P1(k)]\sigma _{B}^{2}(k)=\frac{[m_{G}P_{1}(k)-m(k)]^{2}}{P_{1}(k)[1-P_{1}(k)]},对于k=0~L-1计算类间方差σB2(k)\sigma _{B}^{2}(k)
  6. Otsu阈值K为令σB2(k)\sigma _{B}^{2}(k)最大的k值,若最大值不唯一,则令K为各k值均值。
  7. 将K带入公式η(k)=σB2(k)σG2\eta (k)=\frac{\sigma _{B}^{2}(k)}{\sigma_{G}^{2}},得到可分性测度η(k)\eta (k)
2010-03-04 11:34:00 clhmw 阅读数 1166

最近在做项目,开始接触数字图像处理方面的东西。一时兴起,结合数字图像处理的基本知识和opencv的基本了解,写了一个数字图像处理基本类。类里实现的功能见代码。

 

环境:vs2008 + opencv

 

头文件EDIP.h (Enjoy's Digital Image Processing)

 

EDIP.cpp

 

 

不知道是我理解的有问题还是怎么,Laplace强化处理后,重新标定的结果基色偏黄。

其他功能有待添加

 

2012-09-16 19:05:42 yanhui_wei 阅读数 5322
	php提供了丰富的图像处理函数,主要包括如下几种:

	①获取图像信息的函数
	②创建与销毁图像的函数
	③载入图像的函数
	④输出图像的函数
	⑤分配/取消图像颜色的函数
	⑥拷贝图像的函数
	⑦合并图像的函数
	⑧绘制线段与圆弧的函数
	⑨图像填充函数

	在使用php的图像处理函数之前,需要开启php.ini中的gd2库扩展
	
	extension=php_gd2.dll	

使用gd_info()函数可以查看当前安装的gd库信息:
	<?php
	var_dump(gd_info());
	?>

结果:
array(12) {
	["GD Version"]=>
	string(27) "bundled (2.0.34 compatible)"
	["FreeType Support"]=>
	bool(true)
	["FreeType Linkage"]=>
	string(13) "with freetype"
	["T1Lib Support"]=>
	bool(true)
	["GIF Read Support"]=>
	bool(true)
	["GIF Create Support"]=>
	bool(true)
	["JPG Support"]=>
	bool(true)
	["PNG Support"]=>
	bool(true)
	["WBMP Support"]=>
	bool(true)
	["XPM Support"]=>
	bool(false)
	["XBM Support"]=>
	bool(true)
	["JIS-mapped Japanese Font Support"]=>
	bool(false)
}


	常用函数:

(1)getimagesize():此函数主要用于获取图像的大小及相关信息,成功则返回一个数组,失败则返回false
	语法:
		array getimagesize(string filename);
案例:
	<?php
	$array = getimagesize("images/flower_1.jpg");
	print_r($array);
	?>

结果:
浏览器中的结果:
Array
(
    [0] => 350
    [1] => 318
    [2] => 2
    [3] => width="350" height="318"
    [bits] => 8
    [channels] => 3
    [mime] => image/jpeg
)

返回结果说明
	①索引 0 给出的是图像宽度的像素值
	②索引 1 给出的是图像高度的像素值
	③索引 2 给出的是图像的类型,返回的是数字,其中1 = GIF,2 = JPG,3 = PNG,4 = SWF,5 = PSD,6 = BMP,7 = TIFF(intel byte order),8 = TIFF(motorola byte order),9 = JPC,10 = JP2,11 = JPX,12 = JB2,13 = SWC,14 = IFF,15 = WBMP,16 = XBM
	④索引 3 给出的是一个宽度和高度的字符串,可以直接用于 HTML 的 <image> 标签
	⑤索引 bits 给出的是图像的每种颜色的位数,二进制格式
	⑥索引 channels 给出的是图像的通道值,RGB 图像默认是 3
	⑦索引 mime 给出的是图像的 MIME 信息,此信息可以用来在 HTTP Content-type 头信息中发送正确的信息,
		如: header("Content-type: image/jpeg"); 

(2)imagesx(),imagesy():这两个函数分别用来获取图像的宽度和高度,单位为像素,返回值为整型
	语法:
		int imagesx(resource image)
		int imagesy(resource image)
	注意:
	参数为如 imagecreatetruecolor()、imagecreatefromjpeg() 等函数返回的图像资源
案例:
	<?php
	$img = imagecreatefromjpeg("images/flower_1.jpg");
	echo "图像宽度:",imagesx( $img ),"<br />";
	echo "图像高度:",imagesy( $img );
	?>

浏览器输出: 

图像宽度:350
图像高度:318


(3)如果我们要对图像进行处理,就如其它图像处理软件一样,需要创建一块画布。
	imagecreate()与imagecreatetruecolor()函数用于创建一幅空白图像
	语法:
		resource   imagecreate(int x,int y)
	注意:参数x、y分别代表要创建图像的宽度和高度,返回一个图像资源
案例:
<?
header("Content-type: image/png");
//创建图像
$im = @imagecreate(200, 50) or die("创建图像资源失败");
//图片背景颜色
$bg = imagecolorallocate($im, 255, 255, 255);
//文字颜色
$text_color = imagecolorallocate($im, 0, 0, 255);
//水平画一行字,要输出中文等需要 TTF 字体支持的请使用 magettftext() 函数
imagestring($im, 5, 0, 0, "Hello world!", $text_color);
//以PNG格式输出图像
imagepng($im);
//销毁图像资源
imagedestroy($im);
?>

(4)图像处理完成后,使用imagedestroy()函数销毁图像资源以释放内存
	语法:
		bool   imagedestroy(resource image)

(5)此系列函数用于从文件或url载入一张图像,成功返回一个图像资源,失败返回一个空字符串
该系列函数有:
	①imagecreatefromgif():创建一块画布,并从 GIF 文件或 URL 地址载入一副图像
	②imagecreatefromjpeg():创建一块画布,并从 JPEG 文件或 URL 地址载入一副图像
	③imagecreatefrompng():创建一块画布,并从 PNG 文件或 URL 地址载入一副图像
	④imagecreatefromwbmp()创建一块画布并从 WBMP 文件或 URL 地址载入一副图像
	⑤imagecreatefromstring():创建一块画布,并从字符串中的图像流新建一副图像
语法:
	①resource imagecreatefromgif( string filename )
	②resource imagecreatefromjpeg( string filename )
	③resource imagecreatefrompng( string filename )
	④resource imagecreatefromwbmp( string filename )
	⑤resource imagecreatefromstring( string image )

(6)载入图像案例:
<?
header("Content-type: image/jpeg");
//创建并载入一幅图像
$im = @imagecreatefromjpeg("images/flower_1.jpg");
//错误处理
if(!$im){
    $im  = imagecreatetruecolor(150, 30);
    $bg = imagecolorallocate($im, 255, 255, 255);
    $text_color  = imagecolorallocate($im, 0, 0, 255);
    //填充背景色
    imagefilledrectangle($im, 0, 0, 150, 30, $bg);
    //以图像方式输出错误信息
    imagestring($im, 3, 5, 5, "Error loading image", $text_color);
} else {
    //输出该图像
    imagejpeg($im);
}
?>

此系列函数主要用于以不同格式将图像输出到浏览器或文件
php允许将图像以不同格式输出,该系列函数有:
	①imagegif():以 GIF 格式将图像输出到浏览器或文件
	②imagejpeg():以 JPEG 格式将图像输出到浏览器或文件
	③imagepng():以 PNG 格式将图像输出到浏览器或文件
	④imagewbmp():以 WBMP 格式将图像输出到浏览器或文件
语法:
	①bool imagegif ( resource image [, string filename] )
	②bool imagejpeg ( resource image [, string filename [, int quality]] )
	③bool imagepng ( resource image [, string filename] )
	④bool imagewbmp ( resource image [, string filename [, int foreground]] )

绘制一个圆弧并保存到image目录下:
<?php
header("Content-type: image/png");
$im = @imagecreate(200, 200)or die("创建图像资源失败");
$bg = imagecolorallocate($im, 204, 204, 204);
$red = imagecolorallocate($im, 255, 0, 0);
imagearc($im, 100, 100, 150, 150, 0, 360, $red);
imagepng($im,"images/circle.png");
imagedestroy($im);
?>
在 images 目录下就会生成一个 circle.png 文件。

(7)imagecolorallocate() 函数用于为图像分配颜色,返回一个标识符,代表了由给定的 RGB 成分组成的颜色,如果分配失败则返回 -1
	语法:
		int imagecolorallocate( resource image, int red, int green, int blue )
	注意:
		参数 red,green 和 blue 分别是所需要的颜色的 红,绿,蓝 成分,取值范围 0 - 255

imagecolorallocatealpha()和 imagecolorallocate() 用法相同,但多了一个额外的透明度参数 alpha,其值从 0 到 127。0 表示完全不透明,127 表示完全透明
	语法:
		int imagecolorallocatealpha( resource image, int red, int green, int blue, int alpha )




分配图像颜色案例:
	 <?php
header("Content-type: image/png");
//创建图像
$im = @imagecreate(200, 50) or die("创建图像资源失败");
//图片背景颜色并填充
$bg = imagecolorallocate($im, 204, 204, 204);
//设定文字颜色
$red = imagecolorallocate($im, 255, 0, 0);
//水平画一行字
imagestring($im, 5, 0, 0, "Hello world!", $red);
//以PNG格式输出图像
imagepng($im);
//销毁图像资源
imagedestroy($im);
?>

(8)imagecolordeallocate() 函数用于取消先前由 imagecolorallocate() 和imagecolorallocatealpha() 函数为图像分配的颜色。 
	语法:
		bool imagecolordeallocate( resource image, int color )

案例:
	
	<?
	$im = @imagecreate(200, 50) or die("创建图像资源失败");
	$bg = imagecolorallocate($im, 255, 0, 0);
	imagecolordeallocate($im, $bg);
	?>

imagecopy() 函数用于拷贝图像或图像的一部分,成功返回 true,否则返回 false  
	语法:
		bool imagecopy( resource dst_im, resource src_im, int dst_x, int dst_y, int src_x, int src_y,int src_w, int src_h )


imagecopy() 函数案例:

	  <?php
header("Content-type: image/jpeg");
//创建目标图像
$dst_im = imagecreatetruecolor(150, 150);
//源图像
$src_im = @imagecreatefromjpeg("images/flower_1.jpg");
//拷贝源图像左上角起始 150px 150px
imagecopy( $dst_im, $src_im, 0, 0, 0, 0, 150, 150 );
//输出拷贝后图像
imagejpeg($dst_im);
imagedestroy($dst_im);
imagedestroy($src_im);
?>

(9)imagecopyresized() 函数用于拷贝图像或图像的一部分并调整大小,成功返回 true ,否则返回 false

	语法:
		bool imagecopyresized( resource dst_im, resource src_im, int dst_x, int dst_y, int src_x, int src_y,int dst_w, int dst_h, int src_w, int src_h )
	 
		本函数参数可参看 imagecopy() 函数,只是本函数增加了两个参数(注意顺序): 
		1.dst_w:目标图像的宽度。
		2.dst_h:目标图像的高度。

imagecopyresized() 生成图片缩略图案例:
<?php
header("Content-type: image/jpeg");
//原图文件
$file = "images/flower_1.jpg";
// 缩略图比例
$percent = 0.5;
// 缩略图尺寸
list($width, $height) = getimagesize($file);
$newwidth = $width * $percent;
$newheight = $height * $percent;
// 加载图像
$src_im = @imagecreatefromjpeg($file);
$dst_im = imagecreatetruecolor($newwidth, $newheight);
// 调整大小
imagecopyresized($dst_im, $src_im, 0, 0, 0, 0, $newwidth, $newheight, $width, $height);
//输出缩小后的图像
imagejpeg($dst_im);
imagedestroy($dst_im);
imagedestroy($src_im);
?>

(10)imagecopymerge() 函数用于拷贝并合并图像的一部分,成功返回 true ,否则返回 false
	语法:
		bool imagecopymerge( resource dst_im, resource src_im, int dst_x, int dst_y, int src_x, int src_y,int src_w, int src_h, int pct )


注意:当为 pct = 100 时对于调色板图像本函数和 imagecopy() 完全一样

imagecopymerge() 函数实现水印功能:
<?php
header("Content-type: image/jpeg");
//原始图像
$dst = "images/flower_1.jpg";
//得到原始图片信息
$dst_im = imagecreatefromjpeg($dst);
$dst_info = getimagesize($dst);
//水印图像
$src = "images/logo.gif";
$src_im = imagecreatefromgif($src);
$src_info = getimagesize($src);	
//水印透明度
$alpha = 30;
//合并水印图片
imagecopymerge($dst_im,$src_im,$dst_info[0]-$src_info[0],$dst_info[1]-$src_info[1],0,0,$src_info[0],
$src_info[1],$alpha);
//输出合并后水印图片
imagejpeg($dst_im);
imagedestroy($dst_im);
imagedestroy($src_im);
?>

(11)imageline() 函数用于绘制一条线段。
	语法:
		bool imageline( resource image, int x1, int y1, int x2, int y2, int color )
	注意:
		用 color 颜色在图像 image 中从坐标 x1,y1 到 x2,y2(图像左上角坐标为 0,0)画一条线段。
案例:
<?php
header("Content-type: image/png");
$im = @imagecreate(300, 300)or die("创建图像资源失败");
$bg = imagecolorallocate($im, 204, 204, 204);
$red = imagecolorallocate($im, 255, 0, 0);
imageline($im,0,30,200,30,$red);
imagepng($im);
imagedestroy($im);
?>

(12)imagesetstyle() 设定所有画线的函数(例如 imageline() 和 imagepolygon())在使用特殊颜色 IMG_COLOR_STYLED 或者用 IMG_COLOR_STYLEDBRUSHED 画一行图像时所使用的风格。如果成功则返回 TRUE ,失败则返回 FALSE 
	语法:
		bool imagesetstyle( resource image, array style )
	注意:style 参数是像素组成的数组。
案例:
<?php
header("Content-type: image/png");
$im = @imagecreate(300, 50)or die("创建图像资源失败");
$bg = imagecolorallocate($im, 204, 204, 204);
$red = imagecolorallocate($im, 255, 0, 0);
// 画一条虚线,5 个红色像素,4 个背景像素
$style = array($red, $red, $red, $red, $red, $bg, $bg, $bg, $bg);
imagesetstyle($im, $style);
imageline($im, 0, 20, 200, 20, IMG_COLOR_STYLED);
imagepng($im);
imagedestroy($im);
?>

(13)imagearc() 函数用于绘制椭圆弧(包括圆弧)。 

	语法:
		bool imagearc(resource image, int cx, int cy, int w, int h, int s, int e, int color )



imagearc() 函数用于绘制椭圆弧案例:

<?php
header("Content-type: image/png");
$im = @imagecreate(200, 200)or die("创建图像资源失败");
$bg = imagecolorallocate($im, 204, 204, 204);
$red = imagecolorallocate($im, 255, 0, 0);
imagearc($im, 100, 100, 150, 150, 0, 360, $red);
imagepng($im);
imagedestroy($im);
?>


(14)imagefill() 函数用于区域填充
	语法:
		bool imagefill( resource image, int x, int y, int color )
	注意:
		x,y 分别为填充的起始 x 坐标和 y 坐标,与 x, y 点颜色相同且相邻的点都会被填充。

案例:
<?php
header("Content-type: image/png");
$im = @imagecreatetruecolor(200, 200);
$red = imagecolorallocate($im, 255, 0, 0);
//用 $red 颜色填充图像
imagefill( $im, 0, 0, $red );
imagepng($im);
imagedestroy($im);
?>

(15)imagefilledarc() 函数画一椭圆弧并填充
	语法:
		bool imagefilledarc( resource image, int cx, int cy, int w, int h, int s, int e, int color, int style )
	注意:
		该函数参数用法可参考绘制椭圆弧函数 imagearc() ,只是本函数增加 style 参数表示填充方式



imagefilledarc() 使用案例:

<?php
header('Content-type: image/png');
$im = imagecreatetruecolor(100, 100);
$red = imagecolorallocate($im, 255, 0, 0);
imagefilledarc($im, 50, 50, 100, 50, 0, 360 , $red, IMG_ARC_PIE);
imagepng($im);
imagedestroy($im);
?>

(16)imagefilledrectangle() 函数画一矩形并填充。
	语法:
		bool imagefilledrectangle( resource image, int x1, int y1, int x2, int y2, int color )
	注意:
		x1,y1为左上角左边,x2,y2为右下角坐标。
案例:
	<?php
	header('Content-type: image/png');
	$im = imagecreatetruecolor(200, 200);
	$yellow = imagecolorallocate($im, 255, 255, 0);
	imagefilledrectangle($im, 20, 150, 40, 200, $yellow);
	imagefilledrectangle($im, 50, 80, 70, 200, $yellow);
	imagepng($im);
	imagedestroy($im);
	?>

(17)imagefilledpolygon() 函数画一多边形并填充。
	语法:
		bool imagefilledpolygon( resource image, array points, int num_points, int color )


绘制一个用红色填充的六边形案例:
	<?php
	header('Content-type: image/png');
	$points = array(
            50, 50,	// Point 1 (x, y)
            100, 50, 	// Point 2 (x, y)
            150, 100, 	// Point 3 (x, y)
            150, 150,	// Point 4 (x, y)
            100, 150, 	// Point 5 (x, y)
            50, 100	// Point 6 (x, y)
       );
	$im = imagecreatetruecolor(200, 200);
	$red = imagecolorallocate($im, 255, 0, 0);
	imagefilledpolygon($im, $points, 6, $red);
	imagepng($im);
	imagedestroy($im);
	?>


	问题?

如何创建缩略图?

	创建一个基本的缩略图需要以下5个步骤:
	①将源图像装载到一个php变量中
	②确定原有图像的高度和宽度
	③创建一个具有正确尺寸的空白缩略图
	④复制原有图像到空白缩略图
	⑤使用正确的内容类型显示缩略图
	
	
	
	案例:
	<?php
	$sourceimage="images/1.jpg";
	$original=imagecreatefromjpeg($sourceimage);		//将源图像载入带一个php变量中
	$dims=getimagesize($sourceimage);				//返回图像的宽度和高度
	
	$thumbwidth=200;								//指定缩略图宽度
	$thumbheight=200;								//指定缩略图高度
	
	$thumb=imagecreatetruecolor($thumbwidth,$thumbheight);	//创建一个指定宽度和高度的空白图像,缩略图将被放置在其中
	
	//此函数将图像的一个调整大小后的版本放置到空白缩略图中
	$imagecopyresampled($thumb,$original,0,0,0,0,$thumbwidth,$thumbheight,$dims[0],$dims[1]);//通过此函数生成缩略图
	
	header("content-type:image/jpeg");				//通过header()函数定义输出的内容类型头
	imagejpeg($thumb);							//使用imagejpeg()函数输出完成的缩略图
	imagedestroy($thumb);							//销毁缩略图所占资源
	imagedestroy($original);							//销毁源图所占资源
	?>
	

在gd2函数库中如何输出中文字符串?

	php中的gd2库支持中文,但必须要以utf-8格式的参数来进行传递,如果使用imageString()函数直接绘制中文字符串就会显示乱码,这是因为gd2函数库对中文只能接受utf-8编码格式,并且默认使用了英文的字体,所以要输出中文字符串,就必须对中文字符串进行转码,并设置中文字符使用的字体,否则输出的只能是乱码
	
	php在图像中添加中文字符串应用的是imagettftext()函数,
	
	语法格式:
	
	array imagettftext(resource image,float size,float angle,int x,int y, int color,string fontfile,string text);
	
	参数1:图像资源
	参数2:字体大小
	参数3:字体的角度,顺时针计算,0度为水平,也就是3点钟的方向(由左到右),90度则为由下到上的文字
	参数4:文字的x坐标值
	参数5:文字的y坐标值
	参数6:文字的颜色
	参数7:字体的文件名称
	参数8:字符串内容

	注意:imagettftext()函数只支持utf-8编码,所以在创建文件时必须也要使用utf-8编码格式,这样才能保证中文字符串的正常输出,但是如果页面本身使用的是gb2312编码格式,那么就需要使用iconv()函数对向图片中添加的中文字符串进行编码格式的转换,由gb2312编码转换为utf-8编码。


如何应用gd2函数为图片添加图像水印?

	使用图片作为水印的前提是该图片的背景必须是透明的,否则输出的效果将很不理想。
	图片水印添加的关键是getimagesize()和imagecopy()函数。应用getimagesize()函数获取上传图片和水印图片的大小,通过imagecopy()函数完成图片水印的添加
	
	语法格式:
	
	bool imagecopy(resource dst_im,resource src_im,int dst_x,int dst_y, int src_x ,int src_y,int src_w ,int src_h);
	
	意义:将src_im图像中的坐标从src_x,src_y	开始,宽度为src_w,,高度为src_h的一部分复制到dst_im图像中坐标为dst_x,dst_y的位置上

2018-04-17 08:39:07 weixin_40807247 阅读数 240

生活中大多数看到的彩色图片都是RGB类型,但是在进行图像处理时,需要用到灰度图、HSV、HSI等颜色制式,opencv提供了cvtColor()函数来实现这些功能。

cvtColor函数

此函数的作用是将一个图像从一个颜色空间转换到另一个颜色空间。

首先看一下cvtColor函数定义:

void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0)

参数说明:

  • src: 输入图像;
  • dst: 输出图像;
  • code: 颜色空间转换标识符;
  • dstCn: 目标图像的通道数,该参数为0时,目标图像根据源图像的通道数和具体操作自动决定;

需要说明的是在opencv2.x时颜色空间转换code用的宏定义是CV_前缀开头,而在opencv3.x版本其颜色空间转换code宏定义更改为COLOR_开头,而经验证,2.4.13版本中opencv同时支持这两种形式的写法。故下面表格会将两种code类型同时列出,以供参考:


#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main()
{
	//1 变量定义
	Mat srcImage, image_gray, image_hsc, image_lab;
	//2 读取原始图像并检查图像是否读取成功
	srcImage = imread("demo01.jpg");
	if (srcImage.empty())
	{
		cout << "读取图像有误,请重新输入正确路径!" << endl;
		return -1;
	}
	imshow("源图像srcImage",srcImage);//在窗口显示源图像

	//3 源图像转为灰度图
	//需要说明的是在opencv2.x时颜色空间转换code用的宏定义是CV_前缀开头,而在opencv3.x版本其颜色空间转换code宏定义更改为COLOR_开头
	//void cvtColor( InputArray src, OutputArray dst, int code, int dstCn = 0 );
	//cvtColor(srcImage,image_gray,CV_BGR2GRAY);
	cvtColor(srcImage, image_gray, COLOR_BGR2GRAY);
	imshow("灰度图image_gray",image_gray);

	//4 源图像转为HSV颜色空间
	cvtColor(srcImage,image_hsc,CV_BGR2HSV);
	imshow("HSV颜色空间image_hsc", image_hsc);

	//5 源图像转为Lab颜色空间
	cvtColor(srcImage, image_lab, CV_BGR2Lab);
	imshow("Lab颜色空间image_lab", image_lab);

	//6 保持等待状态
	waitKey(0);
	return 0;
}

运行结果;

========================分割线=======================

在图像处理时,我们接触到的彩色以RGB居多,为了分析图像在某一通道上的特性,需要将图像的颜色通道进行分离,或者是在对某一颜色通道处理后重新进行融合。opencv提供了split()函数来进行颜色通道的分离,提供了merge()函数来进行颜色通道的融合。


1.split()函数


此函数的作用是将一个图像通道进行分离。

首先看一下split()函数定义:

void split(const Mat& m, vector<Mat>& mv );


参数说明:

  • 第一个参数,const Mat&类型的src,填我们需要进行分离的图像;
  • 第二个参数,vector<Mat>类型的mv,填函数的输出数组或者输出的vector容器,即分离后的图像;

========================分割线=======================


2.merge()函数

merge()函数的功能是split()函数的逆向操作,将多个数组合并成一个多通道的数组。

首先看一下merge()函数定义:

void merge(const vector<Mat>& mv, OutputArray dst );


参数说明:

  • 第一个参数,const <Mat>类型的mv填需要被合并的vector容器的阵列,这个mv参数中所有的矩阵必须有着一样的尺寸和深度;说白了就是前面被split()函数分离后的图像通道。
  • 第二个参数,保存为合并后的图像;

========================分割线=======================


3.演示代码

#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <iostream>

using namespace cv;
using namespace std;
/*

此程序共显示9个窗口。
先将RGB图像通道分离,分别显示R、G、B、单个通道;
后将RGB颜色空间转为HSV空间,将HSV图像通道分离,分别显示H、S、V、单个通道;
最后将H、S、V、单个通道重新合并为3通道图像;
*/
int main()
{

	//1 定义相关变量
	Mat srcImage, newImage;//源图像,通道合并后的图像
	Mat srcImage_B, srcImage_G, srcImage_R;//RGB各个通道
	Mat image_H, image_S, image_V;         //H S V各个通道
	vector<Mat> channels_BGR; //vector<Mat> 可以理解为存放Mat类型的容器(数组)
	vector<Mat> channels_HSV;

	//2 读取原始图像并检查图像是否读取成功
	srcImage = imread("demo01.jpg");
	if (srcImage.empty())
	{
		cout << "读取图像错误,请重新输入正确路径" << endl;
		return -1;
	}
	imshow("srcImage源图像",srcImage);//在窗口显示源图像

	//3 对加载的源图像进行通道分离,即把一个3通道图像转换成3个单通道图像
	split(srcImage,channels_BGR);
	//0通道为B分量,1通道为G分量,2通道为R分量。因为:RGB色彩空间在opencv中默认通道顺序为BGR!!! 
	srcImage_B = channels_BGR.at(0);
	srcImage_G = channels_BGR.at(1);
	srcImage_R = channels_BGR.at(2);
	//分别显示R G B各个通道图像
	imshow("srcImage_B通道",srcImage_B);
	imshow("srcImage_G通道", srcImage_G);
	imshow("srcImage_R通道", srcImage_R);

	//4 将BGR颜色空间转换为HSV颜色空间
	Mat image_hsv;
	cvtColor(srcImage,image_hsv,CV_BGR2HSV);
	imshow("HSV颜色空间图像",image_hsv);

	//5 对加载的HSV图像进行通道分离
	split(image_hsv,channels_HSV);
	//0通道为H分量,1通道为S分量,2通道为V分量
	image_H = channels_HSV.at(0);
	image_S = channels_HSV.at(1);
	image_V = channels_HSV.at(2);
	//分别显示H S V各个通道图像
	imshow("image_H通道", image_H);
	imshow("image_S通道", image_S);
	imshow("image_V通道", image_V);

	//6 将3个单通道重新合成一个三通道图像
	merge(channels_HSV,newImage);
	imshow("将H S V通道合并后的图像",newImage);

	//7 保持等待状态
	waitKey(0);
	return 0;
}

======================分割线===============

有的时候,想知道要我们的程序一共运行了多长时间,这个很常用,也很简单,仅仅需要两个函数即可。

opencv里使用getTickCount()与getTickFrequency()函数记录时间;


函数解释:

getTickCount()函数:它返回从操作系统启动到当前所经的计时周期数。

getTickFrequency()函数:返回CPU的频率。


=====================分割线==================

======================分割线===============


opencv里有个Rect类,可以在图像处理过程中经常使用,这里简单介绍它的几种使用方法。

以下列出Rect类中几个常用函数:

  1. size()函数返回矩形的尺寸大小。
  2. area()函数返回矩形的面积,也就是矩形包含的像素点个数。也就是矩形的(宽*高)的值。
  3. contains(Point)能检测点是否在矩形内。
  4. tl()返回矩形左上角的点坐标。即top-left。
  5. br()返回矩形右下角点坐标。即bottom-right。

======================分割线===============

Rect类对象的创建示例

Rect rect(40, 40, 60, 30); 

  • 参数解释:
  • 参数1:创建矩形的最左角的 x-坐标 ;
  • 参数2:创建矩形的最左角的 y-坐标;
  • 参数3:创建矩形的宽;
  • 参数4:创建矩形的高;
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <iostream>

using namespace cv;
using namespace std;



int main()
{
	//1 定义相关变量
	Rect rect(40,40,60,30);
	Point point(10,10);
	Point point2(70,50);
	Rect  rect1(20,20,30,40);
	Rect  rect2(90,30,20,10);
	Size  size(20,20);
	//参数解释:
	//	参数1:创建矩形的最左角的 x - 坐标 ;
	//	参数2:创建矩形的最左角的 y - 坐标;
	//	参数3:创建矩形的宽;
	//	参数4:创建矩形的高;
	//2 Rect类的相关操作
	cout << "矩形rect左上角的横坐标:" << rect.x << endl;
	cout << "矩形rect左上角的纵坐标:" << rect.y << endl;
	cout << "矩形rect的宽度:" << rect.width << endl;
	cout << "矩形rect的高度:" << rect.height << endl;
	cout << "矩形rect的尺寸:" << rect.size() << endl;
	cout << "矩形rect的面积:" << rect.area() << endl;

	cout << "矩形rect左上角的点坐标:" << rect.tl() << endl;
	cout << "矩形rect右下角的点坐标:" << rect.br() << endl;

	//该点在里面则为1,否则为0
	cout << "判断(10,10)这个点在不在这个矩形rect内:" << rect.contains(point) << endl;
	cout << "判断(70,50)这个点在不在矩形rect内:" << rect.contains(point2) << endl;
	
	cout << "矩阵rect与矩阵rect1的交集:" << (rect & rect1) << endl;
	cout << "矩阵rect与矩阵rect2的交集:" << (rect | rect2) << endl;

	cout << "\n矩阵rect2进行平移操作:" << (rect2 + point) << endl;
	cout << "矩形rect2左上角的点坐标:" << rect2.tl() << endl;
	cout << "矩形rect2右下角的点坐标:" << rect2.br() << endl;


	cout << "矩阵rect2进行平移操作:" << (rect2 - point) << endl;
	cout << "矩阵rect2改变尺寸大小操作:" << (rect2 + size) << endl;

	system("pause");
	return 0;
}
=====================END======================

在图像处理的操作中经常会遇到将两幅图像融合成一张图像的问题,在opnecv里利用addWeighted()函数可以很容易实现这个功能。

  • addWeighted()函数中,输入两个图像image1 和 image2。
  • 两个图像可以是任何象素类型,只要它们的类型相同。它们可以是单通道或是三通道,只要它们相符。
  • 且图像尺寸大小必须相同,否则编译会出错!!!

1.addWeighted()函数

此函数的作用是将两幅图像进行融合。计算两个数组的加权和(dst = alpha*src1 + beta*src2 + gamma)。

首先看一下addWeighted()函数定义:

void addWeighted(InputArray src1, double alpha, InputArray src2,

                              double beta, double gamma, OutputArray dst, int dtype=-1);

参数说明

  • 第一个参数:src1,表示进行加权操作的第一个图像对象,输入图片1
  • 第二个参数:double型的alpha,表示第一个图像的加权系数图片1的融合比例。
  • 第三个参数:src2,表示进行加权操作的第二个图像对象,输入图片2
  • 第四个参数:double型的beta,表示第二个图像的加权系数图片2的融合比例。很多情况下,有关系 alpha+beta=1.0。
  • 第五个参数:double型的gamma,表示一个作用到加权和后的图像上的标量,可以理解为加权和后的图像的偏移量。
  • 第六个参数:dst,表示两个图像加权和后的图像,尺寸和图像类型与src1和src2相同,即输出图像
  • 第七个参数:输出阵列的可选深度,有默认值-1。当两个输入数组具有相同的深度时,这个参数设置为-1(默认值),即等同于src1.depth()。
#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>  
#include <opencv2/imgproc/imgproc.hpp>   
#include <iostream>   
using namespace cv;
using namespace std;

int main()
{
	//1 定义相关变量
	Mat lena, lena1;

	//2 读取原始图像并检查图像是否读取成功
	lena = imread("demo01.jpg");
	lena1 = imread("demo01.jpg");;
	if (lena.empty() && lena1.empty())//检测两幅图像是否同时存在
	{
		cout << "读取图像有误,请重新输入正确路径" << endl;
		return -1;
	}
	//3 显示原始图像
	namedWindow("图像1");//创建窗口
	imshow("图像1",lena);

	namedWindow("图像2");//创建窗口
	imshow("图像2", lena1);

	//4 利用
	//void addWeighted(InputArray src1, double alpha, InputArray src2,
	//double beta, double gamma, OutputArray dst, int dtype = -1);
	addWeighted(lena,0.6,lena1,0.4,0,lena); //最后融合效果显示在lena图像上
	/*
	若不想毁坏原始dog图像,也可建立一个与dog图像类型尺寸一样的新图像,将融合后的图像保存到上面。
	建立方法:
	Mat newImage(lena.size(), lena.type());   //newImage与dog类型尺寸相同
	*/
	namedWindow("图像1与图像2融合效果图");
	imshow("图像1与图像2融合效果图", lena);

	//保持等待状态    
	waitKey();
	return 0;
}
=====================分割线==================

程序说明

注意:要融合的两个图像的尺寸与类型必须一致!!!

但处理图像过程中,往往会遇到两幅图像尺寸不一致情况怎么办呢?
别着急,下一节,我将介绍两种方法去解决。

=====================END======================

上一节,我们说到在两幅图像融合时,我们要求这两幅图像必须类型尺寸一致。但是,若遇到两幅图像尺寸不相同时,我们怎么处理呢?

这节,我们通过两种方式解决这个问题。

  1. 重置其中一副图像的尺寸大小,使其两幅图像尺寸一致;
  2. 在较大的图像中设置感兴趣区域ROI,获得与较小的那个图像尺寸一致的区域;
注意:第一种方式会造成其中一副图像发生形变;而第二种方式不会改变两幅图像的尺寸;

==============分割线===========
addWeighted()函数
作用:计算两个数组的加权和(dst = alpha*src1 + beta*src2 + gamma)。即将两幅图像进行融合。
void addWeighted(InputArray src1, double alpha, InputArray src2,
                              double beta, double gamma, OutputArray dst, int dtype=-1);

参数说明

  • 第一个参数:src1,表示进行加权操作的第一个图像对象,输入图片1
  • 第二个参数:double型的alpha,表示第一个图像的加权系数图片1的融合比例;
  • 第三个参数:src2,表示进行加权操作的第二个图像对象,输入图片2
  • 第四个参数:double型的beta,表示第二个图像的加权系数图片2的融合比例。很多情况下,有关系 alpha+beta=1.0;
  • 第五个参数:double型的gamma,表示一个作用到加权和后的图像上的标量,可以理解为加权和后的图像的偏移量;
  • 第六个参数:dst,表示两个图像加权和后的图像,尺寸和图像类型与src1和src2相同,即输出图像
  • 第七个参数:输出阵列的可选深度,有默认值-1。当两个输入数组具有相同的深度时,这个参数设置为-1(默认值),即等同于src1.depth()。
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp> 
#include <iostream> 
using namespace cv;
using namespace std;

int main()
{
	//1 定义相关变量 
	Mat ac, ahand;
	//2 读取原始图像并检查图像是否读取成功  
	ac = imread("demo01.jpg");
	ahand = imread("demo02.jpg");
	if (ahand.empty() && ac.empty())		//检验两幅图像是否同时存在
	{
		cout << "读取图像有误,请重新输入正确路径!\n";
		return -1;
	}
	//3 显示原始图像
	namedWindow("图像1ac");	//创建窗口
	imshow("图像1ac", ac);	//显示窗口
	namedWindow("图像2ahand");
	imshow("图像2ahand", ahand);
	//4 调整ahand的大小与ac的大小一致,融合函数addWeighted()要求输入的两个图形尺寸必须相同  
	resize(ahand, ahand, Size(ac.cols, ac.rows));
	//5 利用addWeighted()函数对两幅图像进行融合
	addWeighted(ac, 0.6, ahand, 0.4, 0, ac); //最后融合效果显示在ac图像上
	/*
	若不想毁坏原始ac图像,也可建立一个与ac图像类型尺寸一样的新图像,将融合后的图像保存到上面。
	建立方法:
	Mat newImage(ac.size(), ac.type());	//newImage与ac类型尺寸相同
	*/
	namedWindow("图像1与图像2融合效果图");
	imshow("图像1与图像2融合效果图", ac);
	//6 保持等待状态 
	waitKey();
	return 0;
}

通过上面的结果,我们可以看出。
同样输入一大一小的两幅图像,我们在大图像上设置感兴趣区域ROI,此部分区域尺寸和小图像(指的的:手图像)尺寸一致。
这样我们就可以利用addWeighted()函数进行融合了。
可以发现,这种方式,对小图像的尺寸没有发生改变,同时我们还可以设置小图像在大图像的什么位置融合。
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp> 
#include <iostream> 
using namespace cv;
using namespace std;
/*
输入的是一大一小的两幅图像,通过将小图像(指的是:手的那副)利用resize()函数,重置其尺寸大小,让它与塔尖的那副大图像尺寸一致。
这样我们就可以利用addWeighted()函数进行融合了。
可以发现,这种方式,对小图像的尺寸进行改变。
*/
int main()
{
	//1 定义相关变量
	Mat ac, ahand;

	//2 读取原始图像并检查图像是否读取成功
	ac = imread("demo02.jpg");//大
	ahand = imread("demo01.jpg");
	if (ahand.empty() && ac.empty())//检验两幅图像是否同时存在
	{
		cout << "读取图像有误,请输入正确路径" << endl;
		return -1;
	}

	//3 显示原始图像
	namedWindow("图像1ac");
	imshow("图像1ac",ac);

	namedWindow("图像2ahand");
	imshow("图像2ahand",ahand);

	//4 利用ROI,获取将要理图像的矩形大小
	Mat imageROT;
//在ac图像左上角(20,40)处(即起点位置),获取同ahand图像尺寸一致的区域  
	imageROT = ac(Rect(20,40,ahand.cols,ahand.rows));

	//5 利用addWeighted()函数对两幅图像进行融合
	addWeighted(ahand,0.6,imageROT,0.4,0,imageROT);
	namedWindow("图像1与图像2融合效果图");
	imshow("图像1与图像2融合效果图", ac);

	//6 保持等待状态   
	waitKey();
	return 0;
}



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