用OpenCV的形态变换( 膨胀、腐蚀、开运算和闭运算)函数morphologyEx
梯度运算即膨胀结果-腐蚀结果:

【注意】对于二值图像来说,必须是前景图像为白色,背景为黑色,否则需要进行反二值化处理
import cv2
import matplotlib.pyplot as plt
import numpy as np
##读入图片
im1 = cv2.imread(r"fiction\xiaozhu.jpg", cv2.IMREAD_GRAYSCALE)
#创建一个5行5列的值全为1 的卷积核
k = np.ones((5,5),np.uint8)
##进行梯度运算
r = cv2.morphologyEx(im1, cv2.MORPH_GRADIENT, k)
##图像展示
plt.subplot(1,2,1)
plt.imshow(im1, cmap="gray")
plt.axis("off")
plt.subplot(1,2,2)
plt.imshow(r, cmap= "gray")
plt.axis("off")
plt.show()

可以计算不同方向的梯度,梯度运算如下图所示:

得出x方向的梯度值和y方向的梯度值后,通过G = sqr(GX2 + GY2)或G = |GX|+G|Y|得到整幅图像的梯度。
cv2.Sobel参数:

【注意】
1、如果梯度为负数,会无法显示,所以计算完梯度之后需要进行取绝对值处理。
2、同时计算x方向和y方向的梯度,通常没有分别计算两个方向梯度后,进行后处理效果好,通常用cv2.addWeighted(src1, alpha, src2, beta, gamma)进行修正。
3、卷积核大小只能为奇数。
import cv2
import numpy as np
im1 = cv2.imread(r"fiction\xiaozhu1.jpg",cv2.IMREAD_GRAYSCALE)
##默认卷积核为3*3,如果写cv2.Sobel(im1, 0, 1, 0)的话,只能取到一侧边界,另一侧边界值为负,会被规整成0
sobelx = cv2.Sobel(im1, cv2.CV_64F, 1, 0,ksize=3)
sobely = cv2.Sobel(im1, cv2.CV_64F, 0, 1,ksize=3)
##取绝对值
cv2.convertScaleAbs(sobelx)
sobelxy = cv2.addWeighted(sobelx, 0.5, sobely, 0.5, 0)
##同时取x、y的sobel算子没有单独计算x、y然后相加的效果好
sobel_tmp = cv2.Sobel(im1, cv2.CV_64F, 1, 1)
cv2.convertScaleAbs(sobel_tmp)
cv2.namedWindow("dx=1", 0)
cv2.namedWindow("dy=1", 0)
cv2.namedWindow("after addWeighted", 0)
cv2.namedWindow("dx=1,dy=1", 0)
cv2.imshow("dx=1", sobelx)
cv2.imshow("dy=1", sobely)
cv2.imshow("after addWeighted", sobelxy)
cv2.imshow("dx=1,dy=1", sobel_tmp)
cv2.waitKey(0)
cv2.destroyAllWindows()


类似sobel算子,但是卷积核系数不同,离目标点越近的像素权重越大,边缘提取的效果比sobel算子好

二者效果对比如下:
import cv2
im1 = cv2.imread(r"fiction\xiaozhu.jpg", cv2.IMREAD_GRAYSCALE)
##Scharr算子提取边缘,scharr相较于sobel算子,靠近核心部分的权值较大,边缘提取的效果更好,x与y不能同时为1
im1x = cv2.Scharr(im1, cv2.CV_64F, 1, 0)
im1y = cv2.Scharr(im1, cv2.CV_64F, 0, 1)
im1x = cv2.convertScaleAbs(im1x)
im1y = cv2.convertScaleAbs(im1y)
im1ScharryXY = cv2.addWeighted(im1x, 0.5, im1y, 0.5, 0)
##拉普拉斯算子
imLap = cv2.Laplacian(im1,cv2.CV_64F)
imLap = cv2.convertScaleAbs(imLap)
##对比sobel算子提取边缘的效果
im1SobelX = cv2.Sobel(im1, cv2.CV_64F, 1, 0)
im1SobelY = cv2.Sobel(im1, cv2.CV_64F, 0, 1)
im1SobelX = cv2.convertScaleAbs(im1SobelX)
im1SobelY = cv2.convertScaleAbs(im1SobelY)
im1SobelXY = cv2.addWeighted(im1SobelX, 0.5, im1SobelY, 0.5, 0)
##sobel算子模拟scharr算子进行边缘提取
im1So_SC_X = cv2.Sobel(im1, cv2.CV_64F, 1, 0, -1)
im1So_SC_Y = cv2.Sobel(im1, cv2.CV_64F, 0, 1, -1)
im1So_SC_X = cv2.convertScaleAbs(im1So_SC_X)
im1So_SC_Y = cv2.convertScaleAbs(im1So_SC_Y)
im1So_SC_XY = cv2.addWeighted(im1So_SC_X, 0.5, im1So_SC_Y, 0.5, 0)
cv2.namedWindow("im1ScharryXY", 0)
cv2.namedWindow("im1SobelXY", 0)
cv2.namedWindow("im1So_SC_XY", 0)
cv2.namedWindow("imLap", 0)
cv2.imshow("im1ScharryXY", im1ScharryXY)
cv2.imshow("im1SobelXY", im1SobelXY)
cv2.imshow("im1So_SC_XY", im1So_SC_XY)
cv2.imshow("imLap", imLap)
cv2.waitKey(0)
cv2.destroyAllWindows()
依次为scharry算子、sobel算子、sobel仿scharry、拉普拉斯算子结果
原理:
1、高斯滤波去噪声
2、平滑后的图像用sobel算子计算梯度,梯度方向如下图所示:

梯度方向一般都与边界垂直,
一般归类为四个方向:垂直、水平,两个对角线

3、去除所有非边界点


4、滞后阈值
选取两个阈值,maxVal和minVal

5、用法,其实就一个函数,cv2.Canny()

import cv2
im1 = cv2.imread(r"fiction\pig2.jpg", cv2.IMREAD_UNCHANGED)
im1 = cv2.Canny(im1, 128, 256)
im2 = cv2.Canny(im1, 0, 256)
im3 = cv2.Canny(im1, 0, 128)
im4 = cv2.Canny(im1, 0, 10)
cv2.namedWindow("128_256",0)
cv2.namedWindow("0_256",0)
cv2.namedWindow("0_128",0)
cv2.namedWindow("0_10",0)
cv2.imshow("128_256",im1)
cv2.imshow("0_256",im2)
cv2.imshow("0_128",im3)
cv2.imshow("0_10",im4)
cv2.waitKey(0)


原图像减去(原图->向下采样->向上采样)
两次采样后图像会被平滑


import cv2
im1 = cv2.imread(r"fiction\xiaozhu.jpg", cv2.IMREAD_GRAYSCALE)
##向下取样,长、宽各变为1/2
im1Low = cv2.pyrDown(im1)
##向上取样,长、宽各变为原来2倍,会变模糊
im1High = cv2.pyrUp(im1Low)
##拉普拉斯金字塔结果
lapPyr = im1-im1High
cv2.namedWindow("im1Low",0)
cv2.namedWindow("im1High",0)
cv2.namedWindow("im1",0)
cv2.namedWindow("lapPyr",0)
cv2.imshow("im1",im1)
cv2.imshow("im1Low",im1Low)
cv2.imshow("lapPyr",lapPyr)
cv2.imshow("im1High",im1High)
cv2.waitKey(0)
cv2.destroyAllWindows()
依次为原图、向下取样一次、向上取样、原图-向上取样结果
可多层构造拉普拉斯金字塔
这是个轮廓检测的方法,注意,边缘和轮廓是不一样的,边缘不一定连续,但是轮廓是连续的。


import cv2
o = cv2.imread(r"fiction\xiaozhu.jpg", cv2.IMREAD_GRAYSCALE)
co = cv2.imread(r"fiction\xiaozhu.jpg", cv2.IMREAD_UNCHANGED)
cco = co.copy()
max_threshold,img = cv2.threshold(o,127,255,cv2.THRESH_BINARY)
##findcounters:原始图像、轮廓检测方式(只检测外轮廓、等级树形式等)、轮廓近似方式
##查找、绘制过程中会改变原图像
counters, hieraichy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
r = cv2.drawContours(co, counters, -1, (255,0,0),6)
cv2.namedWindow("o", 0)
cv2.namedWindow("r", 0)
cv2.imshow("o", cco)
cv2.imshow("r", r)
cv2.waitKey(0)
cv2.destroyAllWindows()

利用傅里叶变换,将o转化为频域
低频为内部信息,高频为边缘信息
通过高通滤波器得到边缘信息
#低频为内部信息,高频为边缘信息
import cv2
import matplotlib.pyplot as plt
import numpy as np
o = cv2.imread(r"fiction\xiaozhu.jpg", cv2.IMREAD_GRAYSCALE)
##利用傅里叶变换,将o转化为频域,cv2.DFT_COMPLEX_OUTPUT返回双通道的结果,包含幅度和频率,第一个通道是实数部分,第二个通道为虚数部分
#dft = cv2.dft(np.float32(o), flags=cv2.DFT_COMPLEX_OUTPUT)
dft = np.fft.fft2(o)
#将频域0点移动到中心
dft1 = np.fft.fftshift(dft)
# result = 20*np.log(cv2.magnitude(dft1[:,:,0], dft1[:,:,1]))
#
# plt.subplot(2,2,1)
# plt.imshow(o, cmap="gray")
#
# plt.subplot(2,2,2)
# plt.imshow(result,cmap="gray")
#
# plt.show()
##通过高通滤波器得到边缘信息
rows,cols = o.shape
crow,ccols = int(rows/2),int(cols/2)
dft1[crow-3:crow+30,ccols-30:ccols+30] = 0
ishift = np.fft.ifftshift(dft1)
iimg = np.fft.ifft2(ishift)
iimg = np.abs(iimg)
plt.subplot(1,2,1)
plt.imshow(o,cmap="gray")
plt.subplot(1,2,2)
plt.imshow(iimg,cmap="gray")
plt.show()

我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我正在尝试设置一个puppet节点,但rubygems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由rubygems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby
我想了解Ruby方法methods()是如何工作的。我尝试使用“ruby方法”在Google上搜索,但这不是我需要的。我也看过ruby-doc.org,但我没有找到这种方法。你能详细解释一下它是如何工作的或者给我一个链接吗?更新我用methods()方法做了实验,得到了这样的结果:'labrat'代码classFirstdeffirst_instance_mymethodenddefself.first_class_mymethodendendclassSecond使用类#returnsavailablemethodslistforclassandancestorsputsSeco
我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer
设置:狂欢ruby1.9.2高线(1.6.13)描述:我已经相当习惯在其他一些项目中使用highline,但已经有几个月没有使用它了。现在,在Ruby1.9.2上全新安装时,它似乎不允许在同一行回答提示。所以以前我会看到类似的东西:require"highline/import"ask"Whatisyourfavoritecolor?"并得到:Whatisyourfavoritecolor?|现在我看到类似的东西:Whatisyourfavoritecolor?|竖线(|)符号是我的终端光标。知道为什么会发生这种变化吗? 最佳答案
我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby1.9+ 关于ruby-主要:Objectwhenrun
我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2
我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)