Canny边缘检测算法是由4步构成,分别介绍如下:
第一步:噪声去除
由于边缘检测很容易受到噪声的影响,所以首先使用高斯滤波器去除噪声,在图像平滑那一章节中已经介绍过。
第二步:计算图像梯度
对平滑后的图像使用 Sobel 算子计算水平方向和竖直方向的一阶导数( 和
)。根据得到的这两幅梯度图(
和
)找到边界的梯度和方向,公式如下:

如果某个像素点是边缘,则其梯度方向总是垂直与边缘垂直。
梯度方向被归为四类:垂直,水平,和两个对角线方向。
第三步:非极大值抑制
在获得梯度的方向和大小之后,对整幅图像进行扫描,去除那些非边界上的点。对每一个像素进行检查,看这个点的梯度是不是周围具有相同梯度方向的点中最大的。如下图所示:

A点位于图像的边缘,在其梯度变化方向,选择像素点B和C,用来检验A点的梯度是否为极大值,若为极大值,则进行保留,否则A点被抑制,最终的结果是具有“细边”的二进制图像。
第四步:滞后阈值
现在要确定真正的边界。 我们设置两个阈值: 和
。
当图像的灰度梯度高于时被认为是真的边界, 低于
的边界会被抛弃。如果介于两者之间的话,就要看这个点是否与某个被确定为真正的边界点相连,如果是就认为它也是边界点,如果不是就抛弃。如下图:

如上图所示,A 高于阈值 所以是真正的边界点,C 虽然低于
但高于
并且与 A 相连,所以也被认为是真正的边界点。而 B 就会被抛弃,因为低于
而且不与真正的边界点相连。所以选择合适的
和
对于能否得到好的结果非常重要。(指定的越大,标准越高,指定的越小,标准越低)
💬API
canny = cv2.Canny(image, threshold1, threshold2)
💎示例:
img = cv2.imread('sun.jpg')
gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
v1 = cv2.Canny(img, 80, 150)
v2 = cv2.Canny(img, 50, 100)
res = np.hstack((v1,v2))
cv2.imshow('res', res)
cv2.waitKey(0) # 等待时间,毫秒级,0表示按任意键终止
cv2.destroyAllWindows()

💬API
cv2.findContours(img,mode,method)
mode:轮廓检索模式
method:轮廓逼近方法
原理
直方图是对数据进行统计的一种方法,并且将统计值组织到一系列实现定义好的 bin 当中。
其中, bin 为直方图中经常用到的一个概念,可以译为 “直条” 或 “组距”,其数值是从数据中计算出的特征统计量,这些数据可以是诸如梯度、方向、色彩或任何其他特征。
图像直方图(Image Histogram)是用以表示数字图像中亮度分布的直方图,标绘了图像中每个亮度值的像素个数。
这种直方图中,横坐标的左侧为较暗的区域,而右侧为较亮的区域。因此一张较暗图片的直方图中的数据多集中于左侧和中间部分,而整体明亮、只有少量阴影的图像则相反。
📌 注意:直方图是根据灰度图进行绘制的,而不是彩色图像。
假设有一张图像的信息(灰度值 0 - 255,已知数字的范围包含 256 个值,于是可以按一定规律将这个范围分割成子区域(也就是 bins)。如:

然后再统计每一个 bin(i) 的像素数目。可以得到下图(其中 x 轴表示 bin,y 轴表示各个 bin 中的像素个数):

直方图的一些术语和细节:
直方图的意义:
直方图的计算和绘制
我们使用OpenCV中的方法统计直方图,并使用matplotlib将其绘制出来。
💬API
cv2.calcHist(images,channels,mask,histSize,ranges[,hist[,accumulate]])
参数:
💎示例:
绘制灰度直方图
# 1 直接以灰度图的方式读入
img = cv2.imread('sun.jpg',0)#0表示灰度图
# 2 统计灰度图
hist = cv2.calcHist([img], [0], None, [256], [0,256])
# 3 绘制灰度图
plt.figure(figsize=(10,6),dpi=100)
plt.plot(hist)
plt.grid()
plt.show()

绘制彩色直方图
img = cv2.imread('sun.jpg')
color=('b', 'g', 'r')
for i,col in enumerate(color):
histr =cv2.calcHist([img],[i], None,[256],[0,256])
plt.plot(histr,color=col)
plt.xlim([0,256])
plt.show()

掩膜是用选定的图像、图形或物体,对要处理的图像进行遮挡,来控制图像 处理的区域。
在数字图像处理中,我们通常使用二维矩阵数组进行掩膜。掩膜是由0和1组成一个二进制图像,利用该掩膜图像要处理的图像进行掩膜,其中1值的区域被处理,0 值区域被屏蔽,不会处理。
掩膜的主要用途是:
掩膜在遥感影像处理中使用较多,当提取道路或者河流,或者房屋时,通过一个掩膜矩阵来对图像进行像素过滤,然后将我们需要的地物或者标志突出显示出来。
我们使用cv.calcHist()来查找完整图像的直方图。
如果要查找图像某些区域的直方图,该怎么办?
只需在要查找直方图的区域上创建一个白色的掩膜图像,否则创建黑色, 然后将其作为掩码mask传递即可。
💎示例:
# 1. 直接以灰度图的方式读入
img = cv2.imread('sun.jpg', 0)
# 2. 创建蒙版
mask = np.zeros(img.shape[:2], np.uint8)
mask[400:650, 200:500] = 255
# 3.掩模
masked_img = cv2.bitwise_and(img,img,mask = mask)
# 4. 统计掩膜后图像的灰度图
mask_histr = cv2.calcHist([img],[0],mask,[256],[1,256])
# 5. 图像展示
fig,axes=plt.subplots(nrows=2,ncols=2,figsize=(10,8))
axes[0,0].imshow(img,cmap=plt.cm.gray)
axes[0,0].set_title("Original image")
axes[0,1].imshow(mask,cmap=plt.cm.gray)
axes[0,1].set_title("Masking data")
axes[1,0].imshow(masked_img,cmap=plt.cm.gray)
axes[1,0].set_title("Post-mask data")
axes[1,1].plot(mask_histr)
axes[1,1].grid()
axes[1,1].set_title("Grayscale histogram")
plt.show()

0x01 原理与应用
想象一下,如果一副图像中的大多数像素点的像素值都集中在某一个小的灰度值值范围之内会怎样呢?
如果一幅图像整体很亮,那所有的像素值的取值个数应该都会很高。所以应该把它的直方图做一个横向拉伸(如下图),就可以扩大图像像素值的分布范围,提高图像的对比度,这就是直方图均衡化要做的事情。
“直方图均衡化”是把原始图像的灰度直方图从比较集中的某个灰度区间变成在更广泛灰度范围内的分布。
直方图均衡化就是对图像进行非线性拉伸,重新分配图像像素值,使一定灰度范围内的像素数量大致相同。
这种方法提高图像整体的对比度,特别是有用数据的像素值分布比较接近时,在X光图像中使用广泛,可以提高骨架结构的显示,另外在曝光过度或不足的图像中可以更好的突出细节。
使用opencv进行直方图统计时,使用的是:
dst = cv.equalizeHist(img)
返回:
💎 示例:
img = cv2.imread('sun.jpg', 0)
dst = cv2.equalizeHist(img)
plt.hist(dst.ravel(),256)
plt.show()

0x01 自适应的直方图均衡化
上述的直方图均衡,我们考虑的是图像的全局对比度。 在进行完直方图均衡化之后,图片背景的对比度被改变了,但是我们丢失了很多信息,所以在许多情况下,这样做的效果并不好。如下图所示,对比下两幅图像中雕像的画面,由于太亮我们丢失了很多信息。

为了解决这个问题, 需要使用自适应的直方图均衡化。
此时, 整幅图像会被分成很多小块,这些小块被称为“tiles”(在 OpenCV 中 tiles 的 大小默认是 8x8),然后再对每一个小块分别进行直方图均衡化。 所以在每一个的区域中, 直方图会集中在某一个小的区域中)。
但如果有噪声的话,噪声会被放大。为了避免这种情况的出现要使用对比度限制。对于每个小块来说,如果直方图中的 bin 超过对比度的上限的话,就把 其中的像素点均匀分散到其他 bins 中,然后在进行直方图均衡化。

最后,为了 去除每一个小块之间的边界,再使用双线性差值,对每一小块进行拼接。
💬API
cv.createCLAHE(clipLimit, tileGridSize)
参数:
💎示例:
img = cv2.imread('sun.jpg', 0)
dst = cv2.equalizeHist(img)
plt.hist(dst.ravel(),256)
clahe = cv2.createCLAHE(clipLimit=2.0,tileGridSize=(8,8))
res_clahe = clahe.apply(img)
res = np.hstack((img, dst, res_clahe))
cv2.imshow('res',res)

总结
1. 灰度直方图:
cv.calcHist(images,channels,mask,histSize,ranges [,hist [,accumulate]])
2. 掩膜
创建蒙版,透过mask进行传递,可获取感兴趣区域的直方图
3. 直方图均衡化:增强图像对比度的一种方法
cv.equalizeHist( ): 输入是灰度图像,输出是直方图均衡图像
4. 自适应的直方图均衡
将整幅图像分成很多小块,然后再对每一个小块分别进行直方图均衡化,最后进行拼接
clahe = cv.createCLAHE(clipLimit, tileGridSize)
我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("
我有带有Logo图像的公司模型has_attached_file:logo我用他们的Logo创建了许多公司。现在,我需要添加新样式has_attached_file:logo,:styles=>{:small=>"30x15>",:medium=>"155x85>"}我是否应该重新上传所有旧数据以重新生成新样式?我不这么认为……或者有什么rake任务可以重新生成样式吗? 最佳答案 参见Thumbnail-Generation.如果rake任务不适合你,你应该能够在控制台中使用一个片段来调用重新处理!关于相关公司
之前在培训新生的时候,windows环境下配置opencv环境一直教的都是网上主流的vsstudio配置属性表,但是这个似乎对新生来说难度略高(虽然个人觉得完全是他们自己的问题),加之暑假之后对cmake实在是爱不释手,且这样配置确实十分简单(其实都不需要配置),故斗胆妄言vscode下配置CV之法。其实极为简单,图比较多所以很长。如果你看此文还配不好,你应该思考一下是不是自己的问题。闲话少说,直接开始。0.CMkae简介有的人到大二了都不知道cmake是什么,我不说是谁。CMake是一个开源免费并且跨平台的构建工具,可以用简单的语句来描述所有平台的编译过程。它能够根据当前所在平台输出对应的m
我正在尝试使用Ruby2.0.0和Rails4.0.0提供的API从imgur中提取图像。我已尝试按照Ruby2.0.0文档中列出的各种方式构建http请求,但均无济于事。代码如下:require'net/http'require'net/https'defimgurheaders={"Authorization"=>"Client-ID"+my_client_id}path="/3/gallery/image/#{img_id}.json"uri=URI("https://api.imgur.com"+path)request,data=Net::HTTP::Get.new(path
2022/8/4更新支持加入水印水印必须包含透明图像,并且水印图像大小要等于原图像的大小pythonconvert_image_to_video.py-f30-mwatermark.pngim_dirout.mkv2022/6/21更新让命令行参数更加易用新的命令行使用方法pythonconvert_image_to_video.py-f30im_dirout.mkvFFMPEG命令行转换一组JPG图像到视频时,是将这组图像视为MJPG流。我需要转换一组PNG图像到视频,FFMPEG就不认了。pyav内置了ffmpeg库,不需要系统带有ffmpeg工具因此我使用ffmpeg的python包装p
有这样的事吗?我想在Ruby程序中使用它。 最佳答案 试试这个http://csl.sublevel3.org/jp2a/此外,Imagemagick可能还有一些东西 关于ruby-是否有将图像文件转换为ASCII艺术的命令行程序或库?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/6510445/
我正在使用Dragonfly在Rails3.1应用程序上处理图像。我正在努力通过url将图像分配给模型。我有一个很好的表格:{:multipart=>true}do|f|%>RemovePicture?Dragonfly的文档指出:Dragonfly提供了一个直接从url分配的访问器:@album.cover_image_url='http://some.url/file.jpg'但是当我在控制台中尝试时:=>#ruby-1.9.2-p290>picture.image_url="http://i.imgur.com/QQiMz.jpg"=>"http://i.imgur.com/QQ
我对图像处理完全陌生。我对JPEG内部是什么以及它是如何工作一无所知。我想知道,是否可以在某处找到执行以下简单操作的ruby代码:打开jpeg文件。遍历每个像素并将其颜色设置为fx绿色。将结果写入另一个文件。我对如何使用ruby-vips库实现这一点特别感兴趣https://github.com/ender672/ruby-vips我的目标-学习如何使用ruby-vips执行基本的图像处理操作(Gamma校正、亮度、色调……)任何指向比“helloworld”更复杂的工作示例的链接——比如ruby-vips的github页面上的链接,我们将不胜感激!如果有ruby-
Organization和Image具有一对一的关系。Image有一个名为filename的列,它存储文件的路径。我在Assets管道中包含这样一个文件:app/assets/other/image.jpg。播种时如何包含此文件的路径?我已经在我的种子文件中尝试过:@organization=...@organization.image.create!(filename:File.open('app/assets/other/image.jpg'))#Ialsotried:#@organization.image.create!(filename:'app/assets/other/i
默认情况下:回形针gem将所有附件存储在公共(public)目录中。出于安全原因,我不想将附件存储在公共(public)目录中,所以我将它们保存在应用程序根目录的uploads目录中:classPost我没有指定url选项,因为我不希望每个图像附件都有一个url。如果指定了url:那么拥有该url的任何人都可以访问该图像。这是不安全的。在user#show页面中:我想实际显示图像。如果我使用所有回形针默认设置,那么我可以这样做,因为图像将在公共(public)目录中并且图像将具有一个url:Someimage:看来,如果我将图像附件保存在公共(public)目录之外并且不指定url(同