OpenCV C++(五)----图像平滑

OpenCV C++(五)----图像平滑,第1张

每一幅图像都包含某种程度的噪声,噪声可以理解为由一种或者多种原因造成的灰 度值的随机变化,如由光子通量的随机性造成的噪声等,在大多数情况下,通过平滑技术(也常称为滤波技术)进行抑制或者去除, 其中具备保持边缘(Edge Preserving)作用的平滑技术得到了更多的关注。常用的平滑处理算法包括基于二维离散卷积高斯平滑、均值平滑,基于统计学方法的中值平滑,具备保持边缘作用的平滑算法的双边滤波、导向滤波等。

I与K的二维离散卷积的计算步骤如下。

显然,高为H1、宽为W1的矩阵I与高为H2、宽为W2的卷积核K 的full卷积结果是一 个高为 H1+H2-1 、宽为 W1+W2-1 的矩阵,一般H2 ≤H1,W2 ≤W1。

从full卷积的计算过程可知, 如果Kflip靠近I 的边界, 那么就会有部分延伸到I之外而导致访问到未定义的值, 忽略边界,只是考虑I能完全覆盖Kflip内的值的情况, 该过程称为valid卷积。

当然, 只有当H2≤H1且W2≤W1时才会存在 valid卷积 。

为了使得到的卷积结果和原图像的高、宽相等,所以通常在计算过程中给Kflip指定 一个“锚点”, 然后将“锚点”循环移至图像矩阵的(r, c) 处, 其中0≤r< H1, 0≤c<W1,接下来对应位置的元素逐个相乘,最后对所有的积进行求和作为输出图像矩阵在 (r, c) 处的输出值。这个卷积过程称为same卷积,

大部分时候,为了更方便地指定卷积核的锚点,通常卷积核的宽、高为奇数,那么可以简单地令中心点为锚点的位置。same卷积是full卷积的一部分,而如果valid卷积存在,那么valid卷积是same卷积的一部分。

对于full卷积和same卷积,矩阵I 边界处的值由于缺乏完整的邻接值,因此卷积运算 在这些区域需要特殊处理,方法是进行边界扩充,有如下几种常用方式。

利用上述不同的边界扩充方式得到的same卷积只是在距离矩阵上、下、左、右四个边界小于卷积核半径的区域内值会不同,所以只要在用卷积运算进行图像处理时,图像的重要信息不要落在距离边界小于卷积核半径的区域内就行。

如果一个卷积核至少由两个尺寸比它小的卷积核full卷积而成,并且在计算过程中在所有边界处均进行扩充零的操作,且满足

其中kerneli的尺寸均比Kernel小,1≤i≤n,则称该卷积核是可分离的。

在图像处理中经常使用这样的卷积核,它可以分离为一维水平方向和一维垂直方向上的卷积核。

(1)full卷积性质

如果卷积核Kernel是可分离的, 且Kernel=kernel1★kernel2, 则有:

(2)same卷积性质

其中

其中,根据可分离卷积的性质,有

理解了上述高斯平滑的过程, 就可以明白OpenCV实现的高斯平滑函数:

从参数的设置可以看出, GaussianBlur 也是通过分离的高斯卷积核实现的,也可以令水平方向和垂直方向上的标准差不相同,但是一般会取相同的标准差。 当平滑窗口比较小时, 对标准差的变化不是很敏感, 得到的高斯平滑效果差别不大; 相反,当平滑窗口 较大时,对标准差的变化很敏感, 得到的高斯平滑效果差别较大 。

利用卷积核 的分离性和卷积的结合律,虽然减少了运算量,但是随着卷积核窗口的增加,计算量仍会继续增大,可以利用图像的积分,实现时间复杂度为O(1)的快速均值平滑。

即任意一个位置的积分等于该位置左上角所有值的和。 利用矩阵的积分,可以计算出矩阵中任意矩形区域的和。

中值滤波最重要的能力是去除椒盐噪声。椒盐噪声是指在图像传输系统中由于解码误差等原因,导致图像中出现孤立的白点或者黑点。

一般来说,如果图像中出现较亮或者较暗的物体,若其大小小于中值平滑的窗口半径,那么它们基本上会被滤掉,而较大的目标则几乎会原封不动地保存下来。

中值平滑需要对邻域中的所有像素点按灰度值排序, 一般比卷积运算要慢。

在OpenCV中同样通过定义函数:

此外, 中值平滑只是排序统计平滑中的一种, 如果将取邻域的中值变为取邻域中的 最小值或者最大值, 显然会使图像变暗或者变亮。 这类方法就是后面要介绍的形态学 处理的基础。

高斯平滑、均值平滑在去除图像噪声时,会使图像的边缘信息变得模糊,接下来就 介绍在图像平滑处理过程中可以保持边缘的平滑算法: 双边滤波和导向滤波。

双边滤波是根据每个位置的邻域, 对该位置构建不同的权重模板。 详细过程如下:

其中0≤h<winH, 0≤w<winW, 且每个位置的空间距离权重模板是相同的。

其中0≤h<winH, 0≤w<winW, 显然每个位置的相似性权重模板是不一样的。

整个过程只在第二步计算相似性权重模板时和双边滤波不同, 但是对图像平滑的效果, 特别是对纹理图像来说, 却有很大的不同。

扩展

循环引导滤波 是一种 迭代 的方法, 本质上是一种多次迭代的联合双边滤波, 只是每次计算相似性权重 模板的依据不一样——利用本次计算的联合双边滤波结果作为下一次联合双边滤波计算 相似性权重模板的依据。

导向滤波在平滑图像的基础上,有良好的保边作用, 而且在细节增强等方面都有良好的表现,在执行时间上也比双边滤波快很多。

主要是平滑图像~~~高斯函数具有五个重要的性质,这些性质使得它在早期图像处理中特别有用.这些性质表明,高斯平滑滤波器无论在空间域还是在频率域都是十分有效的低通滤波器,且在实际图像处理中得到了工程人员的有效使用.高斯函数具有五个十分重要的性质,它们是:

(1)二维高斯函数具有旋转对称性,即滤波器在各个方向上的平滑程度是相同的.一般来说,一幅图像的边缘方向是事先不知道的,因此,在滤波前是无法确定一个方向上比另一方向上需要更多的平滑.旋转对称性意味着高斯平滑滤波器在后续边缘检测中不会偏向任一方向.

(2)高斯函数是单值函数.这表明,高斯滤波器用像素邻域的加权均值来代替该点的像素值,而每一邻域像素点权值是随该点与中心点的距离单调增减的.这一性质是很重要的,因为边缘是一种图像局部特征,如果平滑运算对离算子中心很远的像素点仍然有很大作用,则平滑运算会使图像失真.

(3)高斯函数的付立叶变换频谱是单瓣的.正如下面所示,这一性质是高斯函数付立叶变换等于高斯函数本身这一事实的直接推论.图像常被不希望的高频所污染(噪声和细纹理).而所希望的图像特征(如边缘),既含有低频分量,又含有高频分量.高斯函数付立叶变换的单瓣意味着平滑图像不会被不需要的高频所污染,同时保留了大部分所需.

(4)高斯滤波器宽度(决定着平滑程度)是由参数σ表征的,而且σ和平滑程度的关系是非常简单的.σ越大,高斯滤波器的频带就越宽,平滑程度就越好.通过调节平滑程度参数σ,可在图像特征过分模糊(过平滑)与平滑图像中由于噪声和细纹理所引起的过多的不希望突变量(欠平滑)之间取得折衷.

(5)由于高斯函数的可分离性,大高斯滤波器可以得以有效地实现.二维高斯函数卷积可以分两步来进行,首先将图像与一维高斯函数进行卷积,然后将卷积结果与方向垂直的相同一维高斯函数卷积.因此,二维高斯滤波的计算量随滤波模板宽度成线性增长而不是成平方增长.

硬之城上面应该有这个,可以去看看有没有教程之类的,因为毕竟上面的技术资料型号等都很全面也是最新的,所以能解决很多问题。

尺度不变特征变换 (SIFT) 是最流行和最强大的特征提取算法之一,因为它对尺度、旋转和光照保持不变。它已被广泛应用于视频跟踪、图像拼接、同时定位和映射(SLAM)、运动结构(SFM)等领域。然而,高计算复杂度限制了其在实时系统中的进一步应用。这些系统必须在准确性和性能之间进行权衡以实现实时特征提取。他们采用其他更快但精度较低的算法,如 SURF 和 PCA-SIFT。为了解决这个问题,本文提出了一种使用 CUDA 的 GPU 加速 SIFT,命名为 HartSift,充分利用单机CPU和GPU的计算资源,实现高精度、实时的特征提取。实验表明,在 NIVDIA GTX TITAN Black GPU 上,HartSift 可以根据图像的大小在 314-1057ms (9461-31847fps) 内处理图像。此外,HartSift 分别比 OpenCV-SIFT(CPU 版本)和 SiftGPU(GPU 版本)快 5934-7596 倍和 401-649 倍。同时,HartSift 的性能和 CudaSIFT(迄今为止最快的 GPU 版本)的性能几乎相同,而 HartSift 的准确度远高于 CudaSIFT。

SIFT算法可以提取大量显著特征,这些特征在缩放、旋转、光照和3D视点保持不变,还提供了跨越噪声和仿射失真的稳健匹配。但SIFT的高计算复杂度限制了其在大规模数据和实时系统中的进一步应用。而复杂度较低的算法,如SURF、PCA-SIFT的准确性又不太高。因此,在主流计算平台上实现高精度、实时的SIFT是一个重要而有意义的研究课题。

而SIFT算法具有很好的并行性,可以正确移植到GPU上。因此,在配备GPU的异构计算系统上实现高性能的SIFT具有重要的实用价值。

SIFT 算法包含三个阶段,包括高斯差分(DoG)金字塔的构建、精确的关键点定位和 128 维描述符生成。由于每个阶段都有自己的并行特性,因此必须使用不同的并行粒度和优化来实现高性能。尤其是后两个阶段,负载不平衡不利于GPU优化,会导致性能下降。

本文的主要贡献和创新可以概括如下:

有许多工作尝试在GPU上使用SIFT算法。

然而,为了实现高性能,他们省略了 SIFT 算法的一些重要步骤,例如将输入图像加倍、保持尺度变化的连续性和拟合二次函数以定位准确的关键点信息。作者的实验表明,这些遗漏会导致 SIFT 丢失很多关键点和准确性。

Lowe将输入图像尺寸加倍作为高斯金字塔 的最底层,每个尺度 通过高斯卷积产生:

高斯金字塔确定之后,利用相同Octave的层级相减,得到差分金字塔:

其中 ,在本文中,

检测尺度空间极值

将DoG金字塔每个像素与相邻像素比较,同层8个,上下层9个,若像素是局部最大值或局部最小值,将其视为关键点候选。

去除无效关键点

去除较低对比度和不稳定边缘响应的候选关键点,通过将3D二次函数拟合到附近数据执行子像素插值,以获取精确的位置、比例和主曲率比。

方向分配

将候选关键点周围的梯度累积到36 bins的直方图中,根据每层的尺度计算搜索半径。每个紧邻像素由一个高斯加权窗口加权,梯度方向累计到36 bins的方向直方图中。峰值为主要梯度方向,同时超过峰值80%的局部峰值bin也被视为关键点方向。

对关键点周围像素计算梯度直方图,搜索半径比上一步骤大得多,同样用一个高斯加权函数用于为每个邻居的梯度值分配权重。

根据梯度方向将最终的梯度值累积到一个 360-bin 的圆形方向直方图。最后,直方图将被归一化、平滑并转换为 128D 描述符。

构建金字塔应该保持顺序,以保证尺度空间变化连续性。Acharya和Bjorkman为加快这一过程,牺牲准确性打破构建顺序。考虑到不能使准确性降低,构建顺序在HartSift中保留。

分离卷积核

对于 大小的卷积核处理 大小的图像需要进行 次运算,如果将2D卷积核拆解为两个1D的卷积核,计算量减少至 通过使用共享内存和向量化方法,更容易实现合并全局内存访问并减少一维卷积的冗余访问。

Uber 内核

Uber内核将多个不同任务放到一个物理内核中,在一个内核中并行处理任务,而不需要在内核之间切换。差分金字塔第 层由高斯金字塔第 和第 层决定。将高斯差分金字塔和高斯卷积核封装在单个核中,可以充分挖掘并行性。

线程不需要重复读取高斯金字塔第 层的值,这是由于第 层的值计算完后,结果会放在寄存器内而不是全局内存中。借助Uber内核的优势,我们可以节省 的空间和 的内核运行时间

异构并行

HartSift 采用异构并行方法来加速这一阶段。CPU 和 GPU 将并行协作,构建 DoG 金字塔。

由于GPU处理小图像没有优势,作者将 以下的图像放到CPU处理,大图像放到GPU处理。用户也可以自行设置分离点,确保CPU和GPU负载平衡。

存在两个问题:

负载均衡

Warp是GPU最小并行执行单元,即以锁步方式执行的 32 个线程的集合。若负载不均衡,则warp执行时间取决于最后一个线程完成的时间,warp负载不均衡会导致GPU效率降低。

由于候选关键点分布的随机性,几乎所有经线都包含不同数量的空闲线程。如果这些warp继续处理以下部分,就会出现两个级别的负载不平衡

在去除无效的候选关键点部分时,线程将进行亚像素插值以获得准确的候选关键点信息,从而去除具有低对比度或不稳定边缘响应的关键点候选。换句话说,一些线程会比其他线程更早返回一次。负载不平衡会变得更加严重。

为了突破性能瓶颈,HartSift 引入了重新平衡工作负载和多粒度并行优化。

重新平衡工作负载

当检测到负载不平衡时,HartSift 将通过启动具有适当粒度的新内核并分派每个具有 32 个活动线程的新经线来重新平衡工作负载。

此外,启动三个内核分别处理这三个部分,不仅可以重新平衡工作量,还可以根据不同部分的并行特性提供多粒度的并行。

多粒度并行

重新平衡工作负载优化保证每个内核中的线程和经线被完全加载,多粒度并行优化保证工作负载将平均分配到线程和经线。此外,不同内核的并行粒度取决于工作负载的特性。

HartSift通过将一个线程映射到一个或多个像素,采用与关键点候选检测部分和无效关键点去除部分并行的线程粒度。然而,线程粒度并行会导致方向分配部分的负载不平衡,因为不同关键点的相邻区域半径不同。线程粒度并行会为单个线程分配过多的工作,这在某些情况下限制了硬件资源的利用率。所以在这部分应用混合粒度并行:扭曲粒度构建直方图,线程粒度找出并将主导方向分配给相应的关键点。

基于扭曲的直方图算法

作者针对每个关键点提出了一种基于扭曲粒度和原子操作的高性能直方图算法,以充分利用局部性。

该阶段关键点的邻域半径远大于前一阶段。需要为每个关键点累积数千个邻居到一个 360-bin 直方图。如果采用前一阶段的基于原子扭曲的直方图算法,会对这一阶段的性能产生不同的影响。

HartSift引入了一种atomic-free的直方图算法,进一步提升了这一阶段的性能。

该算法包含三个步骤:

为了消除线程间的负载不平衡,实现全局合并访问,HartSift 使用一个warp 来处理一个keypoint 的所有邻居。当线程计算出它们的方向 bin 时,它们需要根据bin变量的值将梯度值累加到局部直方图。考虑到有如此多的邻居并且一个经线的一些线程可能具有相同的 bin,算法1引入了一种无原子的多键约简方法来累积每个经线的部分和。这种方法可以利用warp级shuffle和vote指令完全消除原子操作和本地同步。它根据bin对经纱的线程进行分组并指定每组具有最低车道的线程作为队长线程。队长线程将保存他们自己的 bin 的部分总和,并将它们并行地累积到驻留在共享内存中的本地直方图,而不会发生 bank 冲突和同步。在遍历所有邻居后,HartSift 将最终的局部直方图复制到驻留在全局内存中的全局直方图。

本文提出了一种GPU上的并行SIFT,命名为Hart-Sift,它可以在单机内同时使用CPU和GPU来实现高精度和实时的特征提取。HartSift根据每个阶段的不同特点,通过适当采用不同的优化策略来提升性能,例如负载均衡、基于warp的直方图算法和不同尺度样本的atomic-free直方图算法等。在NVIDIA GTX TITAN Black GPU上,HartSift可以在314 ~ 1057ms(9461 ~ 31847fps)内提取高精度特征,轻松满足高精度和实时性的苛刻要求。另外,与OpenCV-SIFT和SiftGPU相比,HartSift获得了5934 ~ 7596倍和401 ~ 649倍加速分别。同时,HartSift 和 CudaSIFT 的性能几乎相同,但 HartSift 远比 CudaSIFT 准确。

卷积是一种在信号处理和图像处理中常用的运算技术。它的作用主要有以下几个方面:

1 特征提取:卷积可以通过滑动一个卷积核(也称为滤波器)来提取输入信号的局部特征。卷积核的大小和形状不同,可以提取不同类型的特征。例如,在图像处理中,可以使用边缘检测卷积核来提取图像中的边缘特征。

2 降噪:卷积可以通过滤波器对输入信号进行平滑处理,从而去除噪声。例如,在图像处理中,可以使用高斯滤波器来对图像进行平滑处理,从而去除图像中的噪声。

3 压缩:卷积可以通过降低信号的维度来实现数据压缩。例如,在语音处理中,可以使用卷积将语音信号压缩成更小的维度,从而减少存储空间和计算成本。

mask可以看成是一个图像数组(iplimage),一般是八位的灰度图,如果某个函数参数可以传一个mask的话,代表只对mask中非零(非黑色)部分对应的像素作处理。

比如你只想对的某个圆形区域作处理,则传入一个有圆形填充的mask

可以看下这个例子:

http://blogcsdnnet/longlongago2000/archive/2008/09/19/2950428aspx

以前在论坛看到的一个程序,运行效率不高,你可以试一下:

I = imread('111jpg');

I = double(I);

[height,width] = size(I);

J = I;

conv = zeros(5,5);%高斯卷积核

sigma = 1;%方差

sigma_2 = sigma sigma;%临时变量

sum = 0;

for i = 1:5

for j = 1:5

conv(i,j) = exp((-(i - 3) (i - 3) - (j - 3) (j - 3)) / (2 sigma_2)) / (2 314 sigma_2);%高斯公式

sum = sum + conv(i,j);

end

end

conv = conv/sum;%标准化

%对图像实施高斯滤波

for i = 1:height

for j = 1:width

sum = 0;%临时变量

for k = 1:5

for m = 1:5

if (i - 3 + k) > 0 && (i - 3 + k) <= height && (j - 3 + m) > 0 && (j - 3 + m) < width

sum = sum + conv(k,m) I(i - 3 + k,j - 3 + m);

end

end

end

J(i,j) = sum;

end

end

figure,imshow(J,[])

title('高斯滤波后的结果')

%求梯度

dx = zeros(height,width);%x方向梯度

dy = zeros(height,width);%y方向梯度

d = zeros(height,width);

for i = 1:height - 1

for j = 1:width - 1

dx(i,j) = J(i,j + 1) - J(i,j);

dy(i,j) = J(i + 1,j) - J(i,j);

d(i,j) = sqrt(dx(i,j) dx(i,j) + dy(i,j) dy(i,j));

end

end

figure,imshow(d,[])

title('求梯度后的结果')

%局部非极大值抑制

K = d;%记录进行非极大值抑制后的梯度

%设置图像边缘为不可能的边缘点

for j = 1:width

K(1,j) = 0;

end

for j = 1:width

K(height,j) = 0;

end

for i = 2:width - 1

K(i,1) = 0;

end

for i = 2:width - 1

K(i,width) = 0;

end

for i = 2:height - 1

for j = 2:width - 1

%当前像素点的梯度值为0,则一定不是边缘点

if d(i,j) == 0

K(i,j) = 0;

else

gradX = dx(i,j);%当前点x方向导数

gradY = dy(i,j);%当前点y方向导数

gradTemp = d(i,j);%当前点梯度

%如果Y方向幅度值较大

if abs(gradY) > abs(gradX)

weight = abs(gradX) / abs(gradY);%权重

grad2 = d(i - 1,j);

grad4 = d(i + 1,j);

%如果x、y方向导数符号相同

%像素点位置关系

%g1 g2

% C

% g4 g3

if gradX gradY > 0

grad1 = d(i - 1,j - 1);

grad3 = d(i + 1,j + 1);

else

%如果x、y方向导数符号反

%像素点位置关系

% g2 g1

% C

%g3 g4

grad1 = d(i - 1,j + 1);

grad3 = d(i + 1,j - 1);

end

%如果X方向幅度值较大

else

weight = abs(gradY) / abs(gradX);%权重

grad2 = d(i,j - 1);

grad4 = d(i,j + 1);

%如果x、y方向导数符号相同

%像素点位置关系

%g3

%g4 C g2

% g1

if gradX gradY > 0

grad1 = d(i + 1,j + 1);

grad3 = d(i - 1,j - 1);

else

%如果x、y方向导数符号反

%像素点位置关系

% g1

%g4 C g2

%g3

grad1 = d(i - 1,j + 1);

grad3 = d(i + 1,j - 1);

end

end

%利用grad1-grad4对梯度进行插值

gradTemp1 = weight grad1 + (1 - weight) grad2;

gradTemp2 = weight grad3 + (1 - weight) grad4;

%当前像素的梯度是局部的最大值,可能是边缘点

if gradTemp >= gradTemp1 && gradTemp >= gradTemp2

K(i,j) = gradTemp;

else

%不可能是边缘点

K(i,j) = 0;

end

end

end

end

figure,imshow(K,[])

title('非极大值抑制后的结果')

%定义双阈值:EP_MIN、EP_MAX,且EP_MAX = 2 EP_MIN

EP_MIN = 12;

EP_MAX = EP_MIN 2;

EdgeLarge = zeros(height,width);%记录真边缘

EdgeBetween = zeros(height,width);%记录可能的边缘点

for i = 1:height

for j = 1:width

if K(i,j) >= EP_MAX%小于小阈值,不可能为边缘点

EdgeLarge(i,j) = K(i,j);

else if K(i,j) >= EP_MIN

EdgeBetween(i,j) = K(i,j);

end

end

end

end

%把EdgeLarge的边缘连成连续的轮廓

MAXSIZE = 999999;

Queue = zeros(MAXSIZE,2);%用数组模拟队列

front = 1;%队头

rear = 1;%队尾

edge = zeros(height,width);

for i = 1:height

for j = 1:width

if EdgeLarge(i,j) > 0

%强点入队

Queue(rear,1) = i;

Queue(rear,2) = j;

rear = rear + 1;

edge(i,j) = EdgeLarge(i,j);

EdgeLarge(i,j) = 0;%避免重复计算

end

while front ~= rear%队不空

%队头出队

temp_i = Queue(front,1);

temp_j = Queue(front,2);

front = front + 1;

%8-连通域寻找可能的边缘点

%左上方

if EdgeBetween(temp_i - 1,temp_j - 1) > 0%把在强点周围的弱点变为强点

EdgeLarge(temp_i - 1,temp_j - 1) = K(temp_i - 1,temp_j - 1);

EdgeBetween(temp_i - 1,temp_j - 1) = 0;%避免重复计算

%入队

Queue(rear,1) = temp_i - 1;

Queue(rear,2) = temp_j - 1;

rear = rear + 1;

end

%正上方

if EdgeBetween(temp_i - 1,temp_j) > 0%把在强点周围的弱点变为强点

EdgeLarge(temp_i - 1,temp_j) = K(temp_i - 1,temp_j);

EdgeBetween(temp_i - 1,temp_j) = 0;

%入队

Queue(rear,1) = temp_i - 1;

Queue(rear,2) = temp_j;

rear = rear + 1;

end

%右上方

if EdgeBetween(temp_i - 1,temp_j + 1) > 0%把在强点周围的弱点变为强点

EdgeLarge(temp_i - 1,temp_j + 1) = K(temp_i - 1,temp_j + 1);

EdgeBetween(temp_i - 1,temp_j + 1) = 0;

%入队

Queue(rear,1) = temp_i - 1;

Queue(rear,2) = temp_j + 1;

rear = rear + 1;

end

%正左方

if EdgeBetween(temp_i,temp_j - 1) > 0%把在强点周围的弱点变为强点

EdgeLarge(temp_i,temp_j - 1) = K(temp_i,temp_j - 1);

EdgeBetween(temp_i,temp_j - 1) = 0;

%入队

Queue(rear,1) = temp_i;

Queue(rear,2) = temp_j - 1;

rear = rear + 1;

end

%正右方

if EdgeBetween(temp_i,temp_j + 1) > 0%把在强点周围的弱点变为强点

EdgeLarge(temp_i,temp_j + 1) = K(temp_i,temp_j + 1);

EdgeBetween(temp_i,temp_j + 1) = 0;

%入队

Queue(rear,1) = temp_i;

Queue(rear,2) = temp_j + 1;

rear = rear + 1;

end

%左下方

if EdgeBetween(temp_i + 1,temp_j - 1) > 0%把在强点周围的弱点变为强点

EdgeLarge(temp_i + 1,temp_j - 1) = K(temp_i + 1,temp_j - 1);

EdgeBetween(temp_i + 1,temp_j - 1) = 0;

%入队

Queue(rear,1) = temp_i + 1;

Queue(rear,2) = temp_j - 1;

rear = rear + 1;

end

%正下方

if EdgeBetween(temp_i + 1,temp_j) > 0%把在强点周围的弱点变为强点

EdgeLarge(temp_i + 1,temp_j) = K(temp_i + 1,temp_j);

EdgeBetween(temp_i + 1,temp_j) = 0;

%入队

Queue(rear,1) = temp_i + 1;

Queue(rear,2) = temp_j;

rear = rear + 1;

end

%右下方

if EdgeBetween(temp_i + 1,temp_j + 1) > 0%把在强点周围的弱点变为强点

EdgeLarge(temp_i + 1,temp_j + 1) = K(temp_i + 1,temp_j + 1);

EdgeBetween(temp_i + 1,temp_j + 1) = 0;

%入队

Queue(rear,1) = temp_i + 1;

Queue(rear,2) = temp_j + 1;

rear = rear + 1;

end

end

%下面2行用于观察程序运行的状况

end

end

figure,imshow(edge,[])

title('双阈值后的结果')

欢迎分享,转载请注明来源:品搜搜测评网

原文地址:https://pinsoso.cn/meirong/3480037.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2024-02-29
下一篇2024-02-29

随机推荐

  • 比大牌好的平价抗衰老精华液有哪些?

    我作为一个为化妆品而成为月光族的人,对化妆品和精华液的要求真的很高,因为精华液是女人保养皮肤的根本,从最基础的保湿到抗老,只有坚持用才能拥有一个人人都羡慕的素颜好底子。所以今天我就给大家分享5款平价又好用的精华液,一起来看看吧。olay光感

    2024-04-15
    28100
  • 几千块一罐的贵妇面霜跟几十块的面霜,到底有何差别?

    从几十块钱的妮维雅到上千块钱的海蓝之谜……同样是面霜,那为什么要花天价买贵的呢?平价面霜和贵妇面霜,区别在哪? 我们来看下LAMER和妮维雅的对比。 1 | 看品牌LA MER是雅诗兰黛集团旗下的一个贵妇高端品牌,它的修

    2024-04-15
    24100
  • 精华露怎么用

    1、首先精华露在使用时需要倒在手掌上,将它搓热之后再全部涂抹到脸上,这样可以使精华露中的营养物质和小分子,在掌心的温度下乳化后迅速被肌肤吸收。2、其次就是采用从下往上拍打的方式,来加速肌肤对精华露的吸收。如果是把精华露涂抹在脸上之后随意的用

    2024-04-15
    23700
  • 补水的精华和美白的精华可以叠加使用吗?

    随着时间的流逝,不经意间就会发现,脸上的细纹又增多了,随之而来的还有毛孔变的粗大等问题。感觉用了很多护肤品,还是不能够掩饰时间在面部留下的痕迹。看过抗皱紧致精华排名榜后,才知道需要一款能够带来紧致肌肤的抗皱紧致精华。但是,哪款精华液好用?真

    2024-04-15
    23400
  • 保湿精华凝露 怎么用? 用在哪个步骤呢?

    精华凝露就是精华素,直接涂抹在脸上即可,在肌肤拍完水之后使用。顺序则是:洁面---水---精华凝露---乳液。精华凝露有锁水保湿的作用,凝露质地的精华液看上去就像我们平时所用的啫喱霜,这种质地的精华液通常也是不含油分的,容易推开,好吸收,锁

    2024-04-15
    8900
  • 欧诗漫珍珠白凝乳和珍珠白保湿乳的区别

    欧诗漫珍珠白凝乳和珍珠白保湿乳的区别:1、欧诗漫珍珠白保湿乳液是一种液体,而欧诗漫珍珠白保湿凝露属于面霜类,保湿乳液的质地通常都比较轻盈,而且还比较清爽,涂抹在脸上并没有粘稠感,但保湿凝露与乳液不同,保湿凝露质地比较厚重,擦在脸上有粘腻感。

    2024-04-15
    15300
  • 妮维雅和欧莱雅哪个好?

    妮维雅和欧莱雅各有优势,具体比较如下:1 品牌与公司背景:欧莱雅集团是全球最大的美妆品行业领导者,旗下拥有多个国际知名品牌。而妮维雅公司是德国拜尔斯道夫公司所有的大型全球护肤品与身体护理品品牌。2 产品种类与功效:妮维雅只有基本的保湿功效,

    2024-04-15
    16500

发表评论

登录后才能评论
保存