==============================GUI features in OpenCV==========================
import cv2
import numpy as np
## opencv 处理 images
# 使用cv2.imread() 读图片
#img=cv2.imread('testset/img4.PNG',-1) #第二个参数为flag :cv2.IMREAD_COLOR,cv2.IMREAD_GRAYSCALE,cv2.IMREAD_UNCHANGED 简记为 1,0,-1
# 1(彩色图像,任何透明图像被忽略,默认值),0:灰度模式 -1:加载图像包含alpha通道
#使用cv2.imshow() 展示图片
#cv2.imshow('image',img) #第一个参数为窗口名是一个字符串,第二个参数是要展示的图像
#cv2.waitKey(0) #键盘绑定功能,参数以毫秒为单位的时间,功能为等待任何键盘时间制定的毫秒,如果0被传递,无限等待一个键盘操作。
#cv2.destroyAllWindows() #破坏我们创建的所哟窗口,如果要销毁特定的窗口使用cv2.destroyWindow()来传递确切窗口名称为参数
#使用cv2.imwrite()保存一个图像
#cv2.imwrite('save.png',img) #第一个参数为保存的文件名,第二个参数为要保存的图像
=====================================================================================================
## opencv 处理 videos
# 从相机捕获并显示
# 要捕获视频,您需要创建一个VideoCapture对象。 其参数可以是设备索引或视频文件的名称。
# 设备索引只是指定哪个相机的号码。 通常一个相机将被连接(如我的情况,使用笔记本电脑的内置网络摄像头)。
# 所以我只是通过0(或-1)。 您可以通过1选择第二台相机,依此类推。 别忘了释放捕获。
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
while(True):
# Capture frame-by-frame
ret, frame = cap.read() # 返回一个bool(True / False)。
# 如果frame正确读取,则为True。 所以你可以通过检查这个返回值来检查视频的结尾。
# 没有初始化捕获。 在这种情况下,此代码显示错误。 您可以通过cap.isOpened()方法检查是否已初始化。
# 如果是True,OK。 否则使用cap.open()打开它。
#还可以使用cap.get(propId)方法访问此视频的某些功能,其中propId是从0到18的数字。每个数字表示视频的属性(如果适用于该视频),
# 并且完整的详细信息可以 在这里可以看到:属性标识符。 这些值中的一些可以使用cap.set(propId,value)进行修改。 价值是你想要的新价值。
#例如,我可以通过cap.get(3)和cap.get(4)来检查框架的宽度和高度。 默认情况下给我640x480。 但是我想将其修改为320x240。
# 只需使用ret = cap.set(3,320)和ret = cap.set(4,240)。
# Our operations on the frame come here
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Display the resulting frame
cv2.imshow('frame',gray)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
===========================================================================================
# 从文件中播放视频
import numpy as np
import cv2
cap = cv2.VideoCapture('baby.mp4')
while(cap.isOpened()):
ret, frame = cap.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imshow('frame',gray)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
===============================================================================
#保存一个视频
#创建一个VideoWriter对象。 我们应该指定输出文件名(例如:output.avi)。
那么我们应该指定FourCC代码。 然后应通过每秒帧数(fps)和帧大小。
最后一个是isColor标志。 如果为True,编码器需要彩色帧,否则可以使用灰度帧。
#FourCC是用于指定视频编解码器的4字节代码。 可用的代码列表可以在fourcc.org中找到。 它依赖于平台。
#在Fedora:DIVX,XVID,MJPG,X264,WMV1,WMV2。 (XVID是更优选的,MJPG产生高画质的视频,X264提供非常小的视频)
#FourCC代码作为MJPG的cv2.VideoWriter_fourcc('M','J','P','G')或cv2.VideoWriter_fourcc(*'MJPG)传递。
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
# Define the codec and create VideoWriter object
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi',fourcc, 20.0, (640,480))
while(cap.isOpened()):
ret, frame = cap.read()
if ret==True:
frame = cv2.flip(frame,0)
# write the flipped frame
out.write(frame)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
break
# Release everything if job is finished
cap.release()
out.release()
cv2.destroyAllWindows()
=======================================================================================
# coding:utf-8
# 学习使用OpenCV绘制不同的几何形状
# cv2.line(), cv2.circle() , cv2.rectangle(), cv2.ellipse(), cv2.putText()
#img:想要绘制形状的图像
#颜色:形状的颜色。 对于BGR,将其作为元组传递,例如:(255, 0, 0)为蓝色。 对于灰度级,只需传递标量值即可。
#厚度:线或圆的厚度等。如果为圆形的封闭图形通过 - 1,则会填充形状。 默认厚度 = 1
#lineType:线路类型,是否为8连接,抗锯齿线路等。默认情况下,它是8连接的。
# cv2.LINE_AA给出了对于曲线看起来不错的反锯齿线。
import numpy as np
import cv2
# Create a black image
img = np.zeros((512,512,3), np.uint8)
# Draw a diagonal blue line with thickness of 5 px
#img = cv2.line(img,(0,0),(511,511),(255,0,0),5)
#Draw a rectangle
#img = cv2.rectangle(img,(384,0),(510,128),(0,255,0),3)
# Draw a circle
#img = cv2.circle(img,(447,63), 63, (0,0,255), -1)
#Draw a ellipse
#img = cv2.ellipse(img,(256,256),(100,50),0,0,180,255,-1)
# draw a polygon
#pts = np.array([[10,5],[20,30],[70,20],[50,10]], np.int32)
#pts = pts.reshape((-1,1,2))
#img = cv2.polylines(img,[pts],True,(0,255,255))
# add text to image
#需要指定:要写入的文本数据
#要放置的位置坐标(即数据开始的左下角)。
#字体类型(支持支持的字体检查cv2.putText()文档)
#字体大小(指定字体大小)
#常规的东西,如颜色,厚度,lineType等。为了更好看,lineType = cv2.LINE_AA是推荐的。
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img,'OpenCV',(10,500), font, 4,(255,255,255),2,cv2.LINE_AA)
cv2.imshow('1',img)
cv2.waitKey(0)
=====================================================================================================
#鼠标作为画笔 将要使用的函数为:cv2.setMouseCallback()
#鼠标回调函数做一件事,它画一个圆,我们双击
import cv2
import numpy as np
# mouse callback function
def draw_circle(event,x,y,flags,param):
if event == cv2.EVENT_LBUTTONDBLCLK:
cv2.circle(img,(x,y),100,(255,0,0),-1)
# Create a black image, a window and bind the function to window
img = np.zeros((512,512,3), np.uint8)
cv2.namedWindow('image')
cv2.setMouseCallback('image',draw_circle)
while(1):
cv2.imshow('image',img)
if cv2.waitKey(20) & 0xFF == 27:
break
cv2.destroyAllWindows()
#我们绘制矩形或圆形(取决于我们选择的模式),通过像Paint应用程序一样拖动鼠标。 所以我们的鼠标回调函数有两个部分,
一个是绘制矩形和其他的画圆。 这个具体的例子将有助于创建和理解一些交互式应用程序,如对象跟踪,图像分割等。
import cv2
import numpy as np
drawing = False # true if mouse is pressed
mode = True # if True, draw rectangle. Press 'm' to toggle to curve
ix,iy = -1,-1
# mouse callback function
def draw_circle(event,x,y,flags,param):
global ix,iy,drawing,mode
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
ix,iy = x,y
elif event == cv2.EVENT_MOUSEMOVE:
if drawing == True:
if mode == True:
cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),-1)
else:
cv2.circle(img,(x,y),5,(0,0,255),-1)
elif event == cv2.EVENT_LBUTTONUP:
drawing = False
if mode == True:
cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),-1)
else:
cv2.circle(img,(x,y),5,(0,0,255),-1)
img = np.zeros((512,512,3), np.uint8)
cv2.namedWindow('image')
cv2.setMouseCallback('image',draw_circle)
while(1):
cv2.imshow('image',img)
k = cv2.waitKey(1) & 0xFF
if k == ord('m'):
mode = not mode
elif k == 27:
break
cv2.destroyAllWindows()
================================================================================================================
#轨道栏作为调色板
#有一个窗口,显示颜色和三个轨道,以指定B,G,R颜色中的每一个。您滑动轨迹栏和相应的窗口颜色更改。默认情况下,初始颜色将设置为黑色。
#对于cv2.getTrackbarPos()函数,第一个参数是跟踪栏名称,第二个参数是其附加的窗口名称,第三个参数是默认值,第四个参数是最大值,
第五个是执行的回调函数每次跟踪栏值都会发生变化。回调函数始终具有默认参数,即跟踪栏位置。在我们的例子中,函数什么都不做,所以我们简单地通过。
#轨道栏的另一个重要应用是将其用作按钮或开关。默认情况下,OpenCV没有按钮功能。所以你可以使用trackbar获得这样的功能。
#在我们的应用程序中,我们已经创建了一个开关,其中应用程序仅在开关为ON时工作,否则屏幕始终为黑色。
import cv2
import numpy as np
def nothing(x):
pass
# Create a black image, a window
img = np.zeros((300,512,3), np.uint8)
cv2.namedWindow('image')
# create trackbars for color change
cv2.createTrackbar('R','image',0,255,nothing)
cv2.createTrackbar('G','image',0,255,nothing)
cv2.createTrackbar('B','image',0,255,nothing)
# create switch for ON/OFF functionality
switch = '0 : OFF \n1 : ON'
cv2.createTrackbar(switch, 'image',0,1,nothing)
while(1):
cv2.imshow('image',img)
k = cv2.waitKey(1) & 0xFF
if k == 27:
break
# get current positions of four trackbars
r = cv2.getTrackbarPos('R','image')
g = cv2.getTrackbarPos('G','image')
b = cv2.getTrackbarPos('B','image')
s = cv2.getTrackbarPos(switch,'image')
if s == 0:
img[:] = 0
else:
img[:] = [b,g,r]
cv2.destroyAllWindows()
==============================================================================================
=======================================Core Operations========================================
# 访问或修改像素值
import cv2
import numpy as np
img=cv2.imread('testset/img4.PNG')
#通过其行和列坐标访问像素值。
# 对于BGR图像,它返回一个蓝色,绿色,红色值的数组。
# 对于灰度图像,只需返回相应的强度。
#px=img[100,100]
#print px
#108 109 123
#blue=img[100,100,0]
#print blue
#img[100,100]=[255,255,255]
#print img[100,100]
#访问红值
#print img.item(10,10,2)
# 修改红值
#img.itemset((10,10,2),100)
#img.item(10,10,2)
=======================================访问图片属性============================================
import cv2
import numpy as np
img=cv2.imread('testset/img4.PNG')
print img.shape
print img.size
print img.dtype
=======================================分割和合并图像通道======================================
#当需要时,图像的B,G,R通道可以分成各自的平面。 然后,可以将各个频道合并在一起,再次形成BGR图像
import cv2
import numpy as np
img=cv2.imread('testset/img4.PNG')
b,g,r=cv2.split(img)
img=cv2.merge((b,g,r))
===============================图像周围创建边框=================================================
在图像周围创建边框,像相框,可以使用cv2.copyMakeBorder()函数。但是它具有更多的卷积运算,零填充等应用。此功能有以下参数:
src - 输入图像
顶部,底部,左侧,右侧边框宽度,相应方向上的像素数
borderType - 标记要添加的边框类型。它可以是以下类型:
cv2.BORDER_CONSTANT - 添加一个常量的彩色边框。该值应该作为下一个参数给出。
cv2.BORDER_REFLECT - 边框将镜像反射边框元素,如下所示:fedcba | abcdefgh | hgfedcb
cv2.BORDER_REFLECT_101或cv2.BORDER_DEFAULT - 与上述相同,但略有更改,如下所示:gfedcb | abcdefgh | gfedcba
cv2.BORDER_REPLICATE - 最后一个元素全部复制,如下所示:aaaaaa | abcdefgh | hhhhhhhh
cv2.BORDER_WRAP - 无法解释,将如下所示:cdefgh | abcdefgh | abcdefg
value - 如果边框类型为cv2.BORDER_CONSTANT,则为边框颜色
举例来说:
import cv2
import numpy as np
from matplotlib import pyplot as plt
BLUE = [255,0,0]
img1 = cv2.imread('opencv_logo.png')
replicate = cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_REPLICATE)
reflect = cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_REFLECT)
reflect101 = cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_REFLECT_101)
wrap = cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_WRAP)
constant= cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_CONSTANT,value=BLUE)
plt.subplot(231),plt.imshow(img1,'gray'),plt.title('ORIGINAL')
plt.subplot(232),plt.imshow(replicate,'gray'),plt.title('REPLICATE')
plt.subplot(233),plt.imshow(reflect,'gray'),plt.title('REFLECT')
plt.subplot(234),plt.imshow(reflect101,'gray'),plt.title('REFLECT_101')
plt.subplot(235),plt.imshow(wrap,'gray'),plt.title('WRAP')
plt.subplot(236),plt.imshow(constant,'gray'),plt.title('CONSTANT')
plt.show()
===============================图像算术运算========================================
#OpenCV添加和Numpy添加之间有区别。 OpenCV加法是饱和操作,而Numpy加法是模运算。
x = np.uint8([250])
y = np.uint8([10])
print cv2.add(x,y) # 250+10 = 260 => 255
[[255]]
print x+y # 250+10 = 260 % 256 = 4
[4]
===============================图像混合=============================================
#给图像赋予不同的权重,使得它具有混合或透明的感觉,g(x) = (1 - \alpha)f_{0}(x) + \alpha f_{1}(x)
img1 = cv2.imread('ml.png')
img2 = cv2.imread('opencv_logo.jpg')
dst = cv2.addWeighted(img1,0.7,img2,0.3,0)
cv2.imshow('dst',dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
===============================按位操作==============================================
#把OpenCV标志放在图像之上。 如果我添加两个图像,它将改变颜色。 如果我混合,我会得到一个透明的效果。
#但我希望它是不透明的。 如果是一个矩形区域,我可以像上一章那样使用ROI。 但OpenCV标志不是一个矩形。
#所以你可以按照以下的按位操作来做:
# Load two images
img1 = cv2.imread('messi5.jpg')
img2 = cv2.imread('opencv_logo.png')
# 我想把徽标放在左上角,所以我创建了一个ROI
rows,cols,channels = img2.shape
roi = img1[0:rows, 0:cols ]
# 现在创建一个徽标的掩码,并创建它的反掩码
img2gray = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(img2gray, 10, 255, cv2.THRESH_BINARY)
mask_inv = cv2.bitwise_not(mask)
# Now black-out the area of logo in ROI
img1_bg = cv2.bitwise_and(roi,roi,mask = mask_inv)
# 从标志图像中只取标识区域。
img2_fg = cv2.bitwise_and(img2,img2,mask = mask)
# Put logo in ROI 修改主图
dst = cv2.add(img1_bg,img2_fg)
img1[0:rows, 0:cols ] = dst
cv2.imshow('res',img1)
cv2.waitKey(0)
cv2.destroyAllWindows()
=====================================性能测量与改进技术=================================
cv2.getTickCount函数返回参考事件之后的时钟周期数(如机器开机时)到调用此函数的时刻。
因此,如果在函数执行之前和之后调用它,您将获得用于执行函数的时钟周期数。
cv2.getTickFrequency函数返回时钟周期的频率或每秒的时钟周期数。 所以要在几秒钟内找到执行的时间,
你可以做以下操作:
e1 = cv2.getTickCount()
# your code execution
e2 = cv2.getTickCount()
time = (e2 - e1)/ cv2.getTickFrequency()
-----------------------------------------------------------------------------------------
img1 = cv2.imread('messi5.jpg')
e1 = cv2.getTickCount()
for i in xrange(5,49,2):
img1 = cv2.medianBlur(img1,i)#中值滤波
e2 = cv2.getTickCount()
t = (e2 - e1)/cv2.getTickFrequency()
print t
# Result I got is 0.521107655 seconds
==========================================================================================
===================================利用opencv处理图像=====================================
=====================改变颜色=============================================================
BGR-------->Gray,BGR-------------->HSV
#对于颜色转换,我们使用函数cv2.cvtColor(input_image,flag),其中flag决定转换的类型。
对于BGR --灰色转换,我们使用标志cv2.COLOR_BGR2GRAY。 类似地,对于BGR -- HSV,
我们使用标志cv2.COLOR_BGR2HSV。 要获得其他标志,只需在Python终端中运行以下命令:
>>> import cv2
>>> flags = [i for i in dir(cv2) if i.startswith('COLOR_')]
>>> print flags
=============================对象跟踪=====================================================
#拍摄视频的每一帧
#从BGR转换为HSV色彩空间
#我们为一系列蓝色阈值HSV图像
#现在单独提取蓝色对象
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
while(1):
# Take each frame
_, frame = cap.read()
# Convert BGR to HSV
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# define range of blue color in HSV
lower_blue = np.array([110,50,50])
upper_blue = np.array([130,255,255])
# Threshold the HSV image to get only blue colors
mask = cv2.inRange(hsv, lower_blue, upper_blue)
# Bitwise-AND mask and original image
res = cv2.bitwise_and(frame,frame, mask= mask)
cv2.imshow('frame',frame)
cv2.imshow('mask',mask)
cv2.imshow('res',res)
k = cv2.waitKey(5) & 0xFF
if k == 27:
break
cv2.destroyAllWindows()
=================================图像的几何变换======================================
#OpenCV提供了两个转换函数cv2.warpAffine和cv2.warpPerspective,您可以使用它们进行各种转换。
#cv2.warpAffine需要一个2x3变换矩阵,而cv2.warpPerspective则需要一个3x3的变换矩阵作为输入。
#缩放只是调整图像大小。 为此,OpenCV带有一个函数cv2.resize()。
#可以手动指定图像的大小,也可以指定缩放因子。 使用不同的插值方法。
#优选的插值方法是缩小的cv2.INTER_AREA和用于缩放的cv2.INTER_CUBIC(slow)&cv2.INTER_LINEAR。
#默认情况下,使用的插值方法是cv2.INTER_LINEAR,用于所有调整大小的目的。
您可以使用以下方法之一调整输入图像的大小:
import cv2
import numpy as np
img = cv2.imread('messi5.jpg')
res = cv2.resize(img,None,fx=2, fy=2, interpolation = cv2.INTER_CUBIC)
#OR
height, width = img.shape[:2]
res = cv2.resize(img,(2*width, 2*height), interpolation = cv2.INTER_CUBIC)
-------------------------------------翻译-------------------
#cv2.warpAffine()函数的第三个参数是输出图像的大小,它应该是(width,height)的形式。
#记住width =列数,height =行数。
import cv2
import numpy as np
img = cv2.imread('messi5.jpg',0)
rows,cols = img.shape
M = np.float32([[1,0,100],[0,1,50]])
dst = cv2.warpAffine(img,M,(cols,rows))
cv2.imshow('img',dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
---------------------------------------旋转--------------------------------
img = cv2.imread('messi5.jpg',0)
rows,cols = img.shape
M = cv2.getRotationMatrix2D((cols/2,rows/2),90,1)#旋转90度
dst = cv2.warpAffine(img,M,(cols,rows))
-------------------------------------仿射变换------------------------------------------
#在仿射变换中,原始图像中的所有平行线在输出图像中仍然是平行的。 为了找到转换矩阵,
#我们需要输入图像中的三个点和输出图像中相应的位置。 然后cv2.getAffineTransform将创建一个2x3矩阵,
#传递给cv2.warpAffine。
img = cv2.imread('drawing.png')
rows,cols,ch = img.shape
pts1 = np.float32([[50,50],[200,50],[50,200]])
pts2 = np.float32([[10,100],[200,50],[100,250]])
M = cv2.getAffineTransform(pts1,pts2)
dst = cv2.warpAffine(img,M,(cols,rows))
plt.subplot(121),plt.imshow(img),plt.title('Input')
plt.subplot(122),plt.imshow(dst),plt.title('Output')
plt.show()
-------------------------------------透视转换---------------------------------------------
#对于透视变换,您需要一个3x3变换矩阵。 即使转型后,直线也保持直线。
#要找到此转换矩阵,您需要输入图像上的4点和输出图像上的对应点。 在这4个点中,其中3个不应该共线。
#那么转换矩阵可以通过函数cv2.getPerspectiveTransform找到。
#然后用这个3x3转换矩阵应用cv2.warpPerspective。
img = cv2.imread('sudokusmall.png')
rows,cols,ch = img.shape
pts1 = np.float32([[56,65],[368,52],[28,387],[389,390]])
pts2 = np.float32([[0,0],[300,0],[0,300],[300,300]])
M = cv2.getPerspectiveTransform(pts1,pts2)
dst = cv2.warpPerspective(img,M,(300,300))
plt.subplot(121),plt.imshow(img),plt.title('Input')
plt.subplot(122),plt.imshow(dst),plt.title('Output')
plt.show()
====================================图像阈值=====================================================
#如果像素值大于阈值,则分配一个值(可以是白色),否则分配另一个值(可以是黑色)。 所使用的函数是cv2.threshold。
# 第一个参数是源图像,它应该是灰度图像。 第二个参数是用于对像素值进行分类的阈值。
# 第三个参数是maxVal,它表示如果像素值大于(有时小于)阈值时给出的值。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('gradient.png',0)
ret,thresh1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
ret,thresh2 = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV)
ret,thresh3 = cv2.threshold(img,127,255,cv2.THRESH_TRUNC)
ret,thresh4 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO)
ret,thresh5 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO_INV)
titles = ['Original Image','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]
for i in xrange(6):
plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
=============================自适应阈值===============================================================
#该算法计算图像的小区域的阈值。 所以我们得到不同的相同图像区域的不同的阈值,它给我们更好的结果,对于具有不同照明的图像。
它有三个“特殊”输入参数,只有一个输出参数。
自适应方法 - 它决定如何计算阈值值。
cv2.ADAPTIVE_THRESH_MEAN_C:阈值是邻域的平均值。
cv2.ADAPTIVE_THRESH_GAUSSIAN_C:阈值是权重是高斯窗口的邻域值的加权和。
块大小 - 它决定邻域的大小。
C - 它只是一个常数,它从平均值或加权平均值中减去。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('dave.jpg',0)
img = cv2.medianBlur(img,5)
ret,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
th2 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,\
cv2.THRESH_BINARY,11,2)
th3 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
cv2.THRESH_BINARY,11,2)
titles = ['Original Image', 'Global Thresholding (v = 127)',
'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
images = [img, th1, th2, th3]
for i in xrange(4):
plt.subplot(2,2,i+1),plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
=================================二值化===================================================================
#我们使用cv2.threshold()函数,但通过额外的标志cv2.THRESH_OTSU。对于阈值,只需通过零。
#然后,算法找到最佳阈值,并返回您作为第二个输出retVal。
#如果不使用Otsu阈值,retVal与您使用的阈值相同。
#查看下面的例子。输入图像是嘈杂的图像。在第一种情况下,我应用了全局阈值为127的值。
#在第二种情况下,我直接应用了大津的阈值。在第三种情况下,我用5x5高斯内核过滤图像以去除噪声,然后应用Otsu阈值。
#了解噪声过滤如何改善结果。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('noisy2.png',0)
# global thresholding
ret1,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
# Otsu's thresholding
ret2,th2 = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# Otsu's thresholding after Gaussian filtering
blur = cv2.GaussianBlur(img,(5,5),0)
ret3,th3 = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# plot all the images and their histograms
images = [img, 0, th1,
img, 0, th2,
blur, 0, th3]
titles = ['Original Noisy Image','Histogram','Global Thresholding (v=127)',
'Original Noisy Image','Histogram',"Otsu's Thresholding",
'Gaussian filtered Image','Histogram',"Otsu's Thresholding"]
for i in xrange(3):
plt.subplot(3,3,i*3+1),plt.imshow(images[i*3],'gray')
plt.title(titles[i*3]), plt.xticks([]), plt.yticks([])
plt.subplot(3,3,i*3+2),plt.hist(images[i*3].ravel(),256)
plt.title(titles[i*3+1]), plt.xticks([]), plt.yticks([])
plt.subplot(3,3,i*3+3),plt.imshow(images[i*3+2],'gray')
plt.title(titles[i*3+2]), plt.xticks([]), plt.yticks([])
plt.show()
======================================平滑图像=================================================
#二维卷积(图像过滤)
对于一维信号,图像也可以通过各种低通滤波器(LPF),高通滤波器(HPF)等进行滤波.LFF有助于消除噪声或模糊图像。
HPF滤镜有助于在图像中找到边。
OpenCV提供了一个函数cv2.filter2D()来将内核与图像进行卷积。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('opencv_logo.png')
kernel = np.ones((5,5),np.float32)/25#5x5卷积,平均滤波
dst = cv2.filter2D(img,-1,kernel)
plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(dst),plt.title('Averaging')
plt.xticks([]), plt.yticks([])
plt.show()
=====================================图像模糊(图像平滑)=======================================
图像模糊是通过使用低通滤波器内核卷积图像来实现的。 它有助于消除噪音。
它实际上从图像中去除了高频内容(例如,噪点,边缘),导致当应用滤镜时边缘被模糊。
(嗯,有模糊的技术,不模糊边缘)。
OpenCV主要提供四种模糊技术。
平均
这是通过用标准化的盒式滤波器卷积图像来完成的。 它只需要将内核区域下的所有像素的平均值取代为该平均值的中心元素。
这由函数cv2.blur()或cv2.boxFilter()完成。 如果不想使用标准化的框过滤器,请使用cv2.boxFilter()并将参数normalize = False传递给函数。
我们应该指定内核的宽度和高度。 3x3标准化的盒式过滤器将如下所示:
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('opencv_logo.png')
blur = cv2.blur(img,(5,5))
plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(blur),plt.title('Blurred')
plt.xticks([]), plt.yticks([])
plt.show()
高斯滤波
在这种方法中,代替由相等的滤波器系数组成的盒式滤波器,使用高斯核。 它使用函数cv2.GaussianBlur()完成。
我们应该指定内核的宽度和高度,它应该是正的和奇数的。 我们还应该分别指定X和Y方向的标准差,sigmaX和sigmaY。
如果仅指定sigmaX,则将σigma取为等于sigmaX。 如果两者均为零,则从内核大小计算。
高斯滤波在去除图像中的高斯噪声方面非常有效。
如果需要,可以使用函数cv2.getGaussianKernel()创建一个高斯内核。
上述代码可以修改为高斯模糊:
blur = cv2.GaussianBlur(img,(5,5),0)
中值滤波
这里,函数cv2.medianBlur()计算内核窗口下的所有像素的中值,中心像素被替换为该中值。
这对消除噪音非常有效。 要注意的一个有趣的事情是,在高斯和滤波器中,中心元素的滤波值可以是原始图像中可能不存在的值。
然而,中值滤波并不是这样,因为中心元素总是被图像中的某些像素值替代。 这有效地降低了噪音。 内核大小必须是正的奇整数。
在这个演示中,我们给原始图像增加了50%的噪声,并使用了中值滤波器。 检查结果:
median = cv2.medianBlur(img,5)
双边过滤
我们之前呈现的滤镜往往会模糊边缘。双向滤波器cv2.bilateralFilter()不是这种情况,cv2.bilateralFilter()被定义为,
并且在保留边缘的同时非常有效地进行噪声去除。但与其他过滤器相比,操作较慢。我们已经看到,高斯滤波器在像素周围附近找到一个邻域,
并找到其高斯加权平均值。这个高斯滤波器是单独的空间的函数,也就是在滤波时考虑附近的像素。不考虑像素是否具有几乎相同的强度值,
并且不考虑像素是否位于边缘上。所产生的效果是高斯滤波器倾向于模糊边缘,这是不期望的。
双边滤波器还在空间域中使用高斯滤波器,但它也使用一个(乘法)高斯滤波器分量,它是像素强度差异的函数。
空间的高斯函数确保只有像素是“空间相邻”被用于滤波,而在强度域中应用的高斯分量(强度差的高斯函数)
确保仅具有与中心的强度相似的像素包含像素(“强度邻居”)以计算模糊强度值。结果,该方法保留边缘,
因为对于位于边缘附近的像素,相对于边缘的相邻像素,并且因此与中心像素相比表现出大的强度变化,将不包括模糊。
下面的示例演示了双边过滤的使用
blur = cv2.bilateralFilter(img,9,75,75)
==========================================形态转化=================================================
-----------------------------------------腐蚀------------------------------------------
侵蚀
侵蚀的基本思想就像只有土壤侵蚀,它侵蚀了前景物体的边界(总是尽量保持前景白色)。 那么它是做什么的呢? 内核滑过图像(如2D卷积)。
只有当内核下的所有像素为1时,才能将原始图像(1或0)中的像素视为1,否则将被侵蚀(使为零)。
所以发生的是,边界附近的所有像素将被丢弃,这取决于内核的大小。 因此,前景对象的厚度或尺寸减小,或者仅仅是图像中的白色区域减小。
它有助于去除小白噪声(如我们在颜色空间章节中看到的),分离两个连接的对象等。
import cv2
import numpy as np
img = cv2.imread('j.png',0)
kernel = np.ones((5,5),np.uint8)
erosion = cv2.erode(img,kernel,iterations = 1)
cv2.imshow('erosion',img)
cv2.waitKey(0)
----------------------------------------膨胀----------------------------------------------
#扩张
正好与侵蚀相反。 这里,如果内核下至少有一个像素为“1”,像素元素为“1”。 所以它增加了图像中的白色区域或前景对象的大小增加。
通常,在噪声消除的情况下,侵蚀之后是扩张。 因为侵蚀消除了白色的噪音,而且也缩小了我们的对象。 所以我们扩大它。
由于噪音消失,他们不会回来,但我们的对象面积增加。 它也可用于连接物体的断裂部分。
dilation = cv2.dilate(img,kernel,iterations = 1)
---------------------------------------开放-----------------------------------------------
开放
开放只是另一个侵蚀的名字,随后是扩张。 如上所述,它有助于消除噪音。 这里我们使用函数cv2.morphologyEx()
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
---------------------------------------关闭-----------------------------------------------
关闭
封闭与开放相反,扩张之后是侵蚀。 关闭前景物体中的小孔或物体上的小黑点是有用的。
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
---------------------------------------形态梯度----------------------------------------------
这是图像的扩张和侵蚀的区别。结果将看起来像对象的轮廓。
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
--------------------------------------顶帽------------------------------------------------------
它是输入图像和图像打开之间的区别。 下面的例子是为一个9x9内核完成的
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
----------------------------------------黑帽------------------------------------------------
输入图像和输入图像的关闭是不同的。
blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
---------------------------------------结构元素----------------------------------------------
在Numpy的帮助下,我们在前面的例子中手动创建了一个结构化元素。 它是矩形的。 但是在某些情况下,您可能需要椭圆/圆形的内核。
所以为了这个目的,OpenCV有一个函数cv2.getStructuringElement()。 你只是传递内核的形状和大小,你会得到所需的内核。
cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5))
================================================图像渐变========================================================
OpenCV提供三种类型的梯度滤波器或高通滤波器,Sobel,Scharr和Laplacian。
Sobel和Scharr衍生物
Sobel操作员是高斯平滑加分散操作的联合,因此更能抵抗噪音。 您可以指定要采取的导数的方向,垂直方向或水平方向(分别为参数yorder和xorder)。
您还可以通过参数ksize指定内核的大小。 如果ksize = -1,则使用3x3 Scharr滤波器,该滤波器比3x3 Sobel滤波器更好的结果。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('dave.jpg',0)
laplacian = cv2.Laplacian(img,cv2.CV_64F)
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=5)
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=5)
plt.subplot(2,2,1),plt.imshow(img,cmap = 'gray')
plt.title('Original'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,2),plt.imshow(laplacian,cmap = 'gray')
plt.title('Laplacian'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,3),plt.imshow(sobelx,cmap = 'gray')
plt.title('Sobel X'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,4),plt.imshow(sobely,cmap = 'gray')
plt.title('Sobel Y'), plt.xticks([]), plt.yticks([])
plt.show()
------------------
将黑白转换作为正斜率(它具有正值),而将白 - 黑转换作为负斜率(它具有负值)。
所以当你将数据转换为np.uint8时,所有的负斜率均为零。 简单来说,你错过了这个边缘。
如果要检测到这两个边,更好的选择是将输出数据类型保持为一些较高的形式,如cv2.CV_16S,cv2.CV_64F等,取其绝对值,然后转换回cv2.CV_8U。
下面的代码演示了水平Sobel滤波器的这个过程以及结果的差异。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('box.png',0)
# Output dtype = cv2.CV_8U
sobelx8u = cv2.Sobel(img,cv2.CV_8U,1,0,ksize=5)
# Output dtype = cv2.CV_64F. Then take its absolute and convert to cv2.CV_8U
sobelx64f = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=5)
abs_sobel64f = np.absolute(sobelx64f)
sobel_8u = np.uint8(abs_sobel64f)
plt.subplot(1,3,1),plt.imshow(img,cmap = 'gray')
plt.title('Original'), plt.xticks([]), plt.yticks([])
plt.subplot(1,3,2),plt.imshow(sobelx8u,cmap = 'gray')
plt.title('Sobel CV_8U'), plt.xticks([]), plt.yticks([])
plt.subplot(1,3,3),plt.imshow(sobel_8u,cmap = 'gray')
plt.title('Sobel abs(CV_64F)'), plt.xticks([]), plt.yticks([])
plt.show()
====================================================canny 边缘检测=================================================
#OpenCV将以上所有内容放在单个函数cv2.Canny()中。 我们将看到如何使用它。 第一个参数是我们的输入图像。 第二和第三个参数分别是我们的minVal和maxVal。
#第三个参数是aperture_size。 用于查找图像渐变的Sobel内核的大小。 默认情况下是3。最后一个参数是L2gradient,它指定查找梯度大小的方程。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('messi5.jpg',0)
edges = cv2.Canny(img,100,200)
plt.subplot(121),plt.imshow(img,cmap = 'gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(edges,cmap = 'gray')
plt.title('Edge Image'), plt.xticks([]), plt.yticks([])
plt.show()
====================================================图像金字塔=======================================================
#我们需要处理相同图像的不同分辨率的图像。例如,在像图像中寻找某物的同时,我们不确定图像中的对象将以什么大小显示。
在这种情况下,我们将需要创建一组不同分辨率的图像,并在所有图像中搜索对象。
这些具有不同分辨率的图像被称为图像金字塔(因为当它们保持在堆叠中,最大图像在底部,最小图像在顶部看起来像金字塔)。
有两种图像金字塔。 1)高斯金字塔和2)拉普拉斯金字塔
高斯金字塔中的较高级别(低分辨率)是通过删除较低级别(较高分辨率)图像中的连续行和列来形成的。
然后,较高级别中的每个像素由基础级别中的5个像素与高斯权重的贡献形成。通过这样做,M \ times N图像成为M / 2 \次N / 2图像。
因此,面积减少到原始面积的四分之一。它被称为八度。我们在金字塔上升(即分辨率降低)时,相同的模式继续下去。
类似地,在扩展时,每个层面的面积变成4倍。我们可以使用cv2.pyrDown()和cv2.pyrUp()函数找到高斯金字塔。
img = cv2.imread('messi5.jpg')
lower_reso = cv2.pyrDown(higher_reso)
higher_reso2 = cv2.pyrUp(lower_reso)
----------------------------------------------使用金字塔的图像混合--------------------------------------------------
#金字塔的一个应用是图像混合。 例如,在图像拼接中,您需要将两个图像堆叠在一起,但由于图像之间的不连续性,它可能看起来不太好。
在这种情况下,与金字塔的图像混合可以让您无缝混合,而不会在图像中留下大量数据。 一个典型的例子就是混合了两种水果,橙子和苹果。
现在看看结果来了解我在说什么:
import cv2
import numpy as np,sys
A = cv2.imread('apple.jpg')
B = cv2.imread('orange.jpg')
# generate Gaussian pyramid for A
G = A.copy()
gpA = [G]
for i in xrange(6):
G = cv2.pyrDown(G)
gpA.append(G)
# generate Gaussian pyramid for B
G = B.copy()
gpB = [G]
for i in xrange(6):
G = cv2.pyrDown(G)
gpB.append(G)
# generate Laplacian Pyramid for A
lpA = [gpA[5]]
for i in xrange(5,0,-1):
GE = cv2.pyrUp(gpA[i])
L = cv2.subtract(gpA[i-1],GE)
lpA.append(L)
# generate Laplacian Pyramid for B
lpB = [gpB[5]]
for i in xrange(5,0,-1):
GE = cv2.pyrUp(gpB[i])
L = cv2.subtract(gpB[i-1],GE)
lpB.append(L)
# Now add left and right halves of images in each level
LS = []
for la,lb in zip(lpA,lpB):
rows,cols,dpt = la.shape
ls = np.hstack((la[:,0:cols/2], lb[:,cols/2:]))
LS.append(ls)
# now reconstruct
ls_ = LS[0]
for i in xrange(1,6):
ls_ = cv2.pyrUp(ls_)
ls_ = cv2.add(ls_, LS[i])
# image with direct connecting each half
real = np.hstack((A[:,:cols/2],B[:,cols/2:]))
cv2.imwrite('Pyramid_blending2.jpg',ls_)
cv2.imwrite('Direct_blending.jpg',real)
==============================================opencv中的轮廓=============================================================
#轮廓可以简单地解释为连接所有连续点(沿着边界),具有相同颜色或强度的曲线。 轮廓是形状分析和物体检测和识别的有用工具。
为了更好的准确性,使用二进制图像 所以在找到轮廓之前,应用阈值或边缘检测。
findContours函数修改源图像。 所以如果你想要源图像,即使在找到轮廓之后,已经存储到一些其他的变量。
在OpenCV中,查找轮廓就像从黑色背景中找到白色物体。 所以记住,要找到的对象应该是白色的,背景应该是黑色的。
让我们看看如何找到二进制图像的轮廓:
--------------------------------------------------------------------------------------------------------------------------
要绘制轮廓,使用cv2.drawContours函数。 它也可以用来绘制任何形状,只要你有它的边界点。 它的第一个参数是源图像,
第二个参数是应该作为Python列表传递的轮廓,第三个参数是轮廓的索引(在绘制单个轮廓时有用)绘制所有轮廓,传递-1),
剩余的参数是颜色,厚度 等等
绘制图像中的所有轮廓:
img = cv2.drawContours(img,轮廓,-1,(0,255,0),3)
绘制个别轮廓,说第4轮廓:
img = cv2.drawContours(img,轮廓,3,(0,255,0),3)
但大多数时候,下面的方法将是有用的:
cnt =轮廓[4]
img = cv2.drawContours(img,[cnt],0,(0,255,0),3)
----------------------------------------------------------------------------------------------------------------------------
import cv2
im = cv2.imread('testset/img4.PNG')
imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray,127,255,0)
image, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
img = cv2.drawContours(image, contours, -1, (0,255,0), 3)
#2 img = cv2.drawContours(image, contours, 3, (0,255,0), 3)
#3 cnt = contours[4]
#3 img = cv2.drawContours(image, [cnt], 0, (0,255,0), 3)
cv2.imshow('as',img)
cv2.waitKey(0)
---------------------------------------------------轮廓特征-------------------------------------------------------------------
---------------------------------------------图像时刻
import cv2
import numpy as np
img = cv2.imread('star.jpg',0)
ret,thresh = cv2.threshold(img,127,255,0)
contours,hierarchy = cv2.findContours(thresh, 1, 2)
cnt = contours[0]
M = cv2.moments(cnt)
print M
---------------------------------------------图像轮廓
area = cv2.contourArea(cnt)
---------------------------------------------图像周长
perimeter = cv2.arcLength(cnt,True)
---------------------------------------------图像近似
假设您正在尝试在图像中找到一个正方形,但是由于图像中存在一些问题,您没有获得一个完美的方形,而是一个“坏的形状”(如下图所示)。
现在您可以使用此功能近似形状。 在这里,第二个参数称为epsilon,它是从轮廓到近似轮廓的最大距离。 这是一个精度参数。
需要一个明智的选择来获得正确的输出。
epsilon = 0.1*cv2.arcLength(cnt,True)
approx = cv2.approxPolyDP(cnt,epsilon,True)
---------------------------------------------凸包
看起来类似于轮廓近似,但它不是(两者可能在某些情况下提供相同的结果)。 这里,cv2.convexHull()函数检查一个曲线的凸性缺陷并进行修正。
一般来说,凸曲线是总是凸出的或至少平坦的曲线。 如果内部膨胀,则称为凸面缺陷。
hull = cv2.convexHull(points[, hull[, clockwise[, returnPoints]]
Arguments details:
points are the contours we pass into.
hull is the output, normally we avoid it.
clockwise : Orientation flag. If it is True, the output convex hull is oriented clockwise.
Otherwise, it is oriented counter-clockwise.
returnPoints : By default, True. Then it returns the coordinates of the hull points.
If False, it returns the indices of contour points corresponding to the hull points.
hull = cv2.convexHull(cnt)
但是如果要查找凸性缺陷,则需要传递returnPoints = False。要理解它,我们将把上面的矩形图像。首先我发现它的轮廓为cnt。
现在我发现它的凸包具有returnPoints = True,我得到以下值:[[[234 202]],[[51 202]],[[51 79]],[[234 79]]]矩形点。
现在如果对returnPoints = False做同样的,我得到以下结果:[[129],[67],[0],[142]]。这些是轮廓中相应点的指标。
例如,检查与第一个结果相同的第一个值:cnt [129] = [[234,202]](对于其他结果,等等)。
-------------------------------------------旋转矩形
以最小面积绘制边界矩形,因此也考虑旋转。 使用的功能是cv2.minAreaRect()。 它返回一个Box2D结构,其包含以下detals - (左上角(x,y),(宽度,高度),旋转角度)。
但是要绘制这个矩形,我们需要矩形的四个角。 它是通过函数cv2.boxPoints()获得的
rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
box = np.int0(box)
im = cv2.drawContours(im,[box],0,(0,0,255),2)
-------------------------------------------最小封闭圆圈
#我们使用函数cv2.minEnclosingCircle()找到对象的外接圆。 它是一个圆形,完全覆盖最小面积的物体。
(x,y),radius = cv2.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
img = cv2.circle(img,center,radius,(0,255,0),2)
-------------------------------------------拟合的椭圆
将一个椭圆适合于一个对象。 它返回旋转的矩形,其中刻有椭圆。
ellipse = cv2.fitEllipse(cnt)
im = cv2.ellipse(im,ellipse,(0,255,0),2)
-------------------------------------------直线拟合
我们可以将一条线适合一组点。 图像下方包含一组白点。 我们可以近似一条直线。
rows,cols = img.shape[:2]
[vx,vy,x,y] = cv2.fitLine(cnt, cv2.DIST_L2,0,0.01,0.01)
lefty = int((-x*vy/vx) + y)
righty = int(((cols-x)*vy/vx)+y)
img = cv2.line(img,(cols-1,righty),(0,lefty),(0,255,0),2)
------------------------------------------轮廓属性
---------------------长宽比
x,y,w,h = cv2.boundingRect(cnt)
aspect_ratio = float(w)/h
---------------------幅度
area = cv2.contourArea(cnt)
x,y,w,h = cv2.boundingRect(cnt)
rect_area = w*h
extent = float(area)/rect_area
---------------------密实度
area = cv2.contourArea(cnt)
hull = cv2.convexHull(cnt)
hull_area = cv2.contourArea(hull)
solidity = float(area)/hull_area
--------------------等效直径
area = cv2.contourArea(cnt)
equi_diameter = np.sqrt(4*area/np.pi)
--------------------方向
(x,y),(MA,ma),angle = cv2.fitEllipse(cnt)
--------------------面具和像素点
mask = np.zeros(imgray.shape,np.uint8)
cv2.drawContours(mask,[cnt],0,255,-1)
pixelpoints = np.transpose(np.nonzero(mask))
#pixelpoints = cv2.findNonZero(mask)
--------------------最大值,最小值及其位置
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(imgray,mask = mask)
--------------------平均颜色或平均强度
mean_val = cv2.mean(im,mask = mask)
--------------------极点
leftmost = tuple(cnt[cnt[:,:,0].argmin()][0])
rightmost = tuple(cnt[cnt[:,:,0].argmax()][0])
topmost = tuple(cnt[cnt[:,:,1].argmin()][0])
bottommost = tuple(cnt[cnt[:,:,1].argmax()][0])
----------------------------------------轮廓:更多功能
---------------------------凸型缺陷
#OpenCV带有一个现成的函数来找到这个,cv2.convexityDefects()。 基本的函数调用如下所示:
hull = cv2.convexHull(cnt,returnPoints = False)
defects = cv2.convexityDefects(cnt,hull)
注意
记住我们必须在找到凸包时传递returnPoints = False,才能找到凸性缺陷。
它返回一个数组,其中每行包含这些值 - [起始点,终点,最远点,到最远点的近似距离]。
我们可以使用图像进行可视化。 我们画一条加入起点和终点的线,然后在最远点画一个圆。 记住返回的前三个值是cnt的索引。
所以我们必须把这些值从cnt。
import cv2
import numpy as np
img = cv2.imread('star.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(img_gray, 127, 255,0)
contours,hierarchy = cv2.findContours(thresh,2,1)
cnt = contours[0]
hull = cv2.convexHull(cnt,returnPoints = False)
defects = cv2.convexityDefects(cnt,hull)
for i in range(defects.shape[0]):
s,e,f,d = defects[i,0]
start = tuple(cnt[s][0])
end = tuple(cnt[e][0])
far = tuple(cnt[f][0])
cv2.line(img,start,end,[0,255,0],2)
cv2.circle(img,far,5,[0,0,255],-1)
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
--------------------------------------------点多边测试
该功能可以找到图像中某个点与轮廓之间的最短距离。 当点在轮廓外部时,返回的距离为负,当点在内部时为正,如果点在轮廓上,则为零。
例如,我们可以检查点(50,50)如下:
dist = cv2.pointPolygonTest(cnt,(50,50),True)
在函数中,第三个参数是measureDist。 如果为True,则找到已签名的距离。
如果为False,则会发现该点是在内部还是外部还是在轮廓上(分别返回+1,-1,0)。
注意
如果您不想找距离,请确保第三个参数为False,因为这是一个耗时的过程。 所以,使它成为假提供2-3倍加速。
--------------------------------------------匹配形状
OpenCV带有一个函数cv2.matchShapes(),使我们能够比较两个形状或两个轮廓,并返回一个显示相似度的度量。
结果越低,匹配越好。 它是根据hu-moment值计算的。
import cv2
import numpy as np
img1 = cv2.imread('star.jpg',0)
img2 = cv2.imread('star2.jpg',0)
ret, thresh = cv2.threshold(img1, 127, 255,0)
ret, thresh2 = cv2.threshold(img2, 127, 255,0)
contours,hierarchy = cv2.findContours(thresh,2,1)
cnt1 = contours[0]
contours,hierarchy = cv2.findContours(thresh2,2,1)
cnt2 = contours[0]
ret = cv2.matchShapes(cnt1,cnt2,1,0.0)
print ret
==================================================opencv中的直方图=================================================
-------------------------------------直方图1:查找,绘制,分析
使用matplotlib
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('home.jpg',0)
plt.hist(img.ravel(),256,[0,256]); plt.show()
使用opencv
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('home.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()
mask的使用
我们使用cv2.calcHist()来查找完整图像的直方图。 如果要查找图像的某些区域的直方图怎么办?
只需在要查找直方图的区域上创建一个带有白色的蒙版图像,否则为黑色。 然后把它当作面具。
img = cv2.imread('home.jpg',0)
# create a mask
mask = np.zeros(img.shape[:2], np.uint8)
mask[100:300, 100:400] = 255
masked_img = cv2.bitwise_and(img,img,mask = mask)
# Calculate histogram with mask and without mask
# Check third argument for mask
hist_full = cv2.calcHist([img],[0],None,[256],[0,256])
hist_mask = cv2.calcHist([img],[0],mask,[256],[0,256])
plt.subplot(221), plt.imshow(img, 'gray')
plt.subplot(222), plt.imshow(mask,'gray')
plt.subplot(223), plt.imshow(masked_img, 'gray')
plt.subplot(224), plt.plot(hist_full), plt.plot(hist_mask)
plt.xlim([0,256])
plt.show()
------------------------------------------直方图均衡
考虑其像素值仅限于特定值范围的图像。 例如,较亮的图像将所有像素都限制在高值。 但是,一个好的图像将会有来自图像所有区域的像素。
所以你需要将这个直方图拉伸到两端(如下图所示,从维基百科),这就是直方图均衡所做的(简单的话)。 这通常会改善图像的对比度。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('wiki.jpg',0)
hist,bins = np.histogram(img.flatten(),256,[0,256])
cdf = hist.cumsum()
cdf_normalized = cdf * hist.max()/ cdf.max()
plt.plot(cdf_normalized, color = 'b')
plt.hist(img.flatten(),256,[0,256], color = 'r')
plt.xlim([0,256])
plt.legend(('cdf','histogram'), loc = 'upper left')
plt.show()
可以看到直方图位于较亮的区域。 我们需要全谱。 为此,我们需要一个转换函数,将更亮区域中的输入像素映射到全区域的输出像素。
那就是直方图均衡。
现在我们找到最小直方图值(不包括0),并应用维基页面中给出的直方图均衡方程。 但是我在这里使用了来自Numpy的掩码数组概念数组。
对于屏蔽阵列,所有操作都在非屏蔽元素上执行。
cdf_m = np.ma.masked_equal(cdf,0)
cdf_m = (cdf_m - cdf_m.min())*255/(cdf_m.max()-cdf_m.min())
cdf = np.ma.filled(cdf_m,0).astype('uint8')
------------------------------------------------OpenCV中的直方图均衡
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('wiki.jpg',0)
equ = cv2.equalizeHist(img)
res = np.hstack((img,equ)) #stacking images side-by-side
cv2.imwrite('res.png',res)
------------------------------------------------- 对比度有限自适应直方图均衡
import numpy as np
import cv2
img = cv2.imread('tsukuba_l.png',0)
# create a CLAHE object (Arguments are optional).
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
cl1 = clahe.apply(img)
cv2.imwrite('clahe_2.jpg',cl1)
---------------------------------------------------二维直方图
cv2.calcHist()。 对于颜色直方图,我们需要将图像从BGR转换为HSV。 (记住,对于1D直方图,我们从BGR转换为灰度)。
对于2D直方图,其参数将被修改如下:
channel = [0,1],因为我们需要处理H和S平面。
bins= [180,256] 180,H平面为256,S平面为256。
range = [0,180,0,256]色相值介于0和180之间,饱和度介于0和256之间。
import cv2
import numpy as np
img = cv2.imread('home.jpg')
hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
hist = cv2.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
二维直方图用numpy
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('home.jpg')
hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
hist, xbins, ybins = np.histogram2d(h.ravel(),s.ravel(),[180,256],[[0,180],[0,256]])
画二维直方图
Using cv2.imshow()
Using Matplotlib
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('home.jpg')
hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
hist = cv2.calcHist( [hsv], [0, 1], None, [180, 256], [0, 180, 0, 256] )
plt.imshow(hist,interpolation = 'nearest')
plt.show()
------------------------------------------直方图反投影
import cv2
import numpy as np
roi = cv2.imread('rose_red.png')
hsv = cv2.cvtColor(roi,cv2.COLOR_BGR2HSV)
target = cv2.imread('rose.png')
hsvt = cv2.cvtColor(target,cv2.COLOR_BGR2HSV)
# calculating object histogram
roihist = cv2.calcHist([hsv],[0, 1], None, [180, 256], [0, 180, 0, 256] )
# normalize histogram and apply backprojection
cv2.normalize(roihist,roihist,0,255,cv2.NORM_MINMAX)
dst = cv2.calcBackProject([hsvt],[0,1],roihist,[0,180,0,256],1)
# Now convolute with circular disc
disc = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
cv2.filter2D(dst,-1,disc,dst)
# threshold and binary AND
ret,thresh = cv2.threshold(dst,50,255,0)
thresh = cv2.merge((thresh,thresh,thresh))
res = cv2.bitwise_and(target,thresh)
res = np.vstack((target,thresh,res))
cv2.imwrite('res.jpg',res)
================================================opencv 中的图像变换
------------------------------------傅里叶变换
# Numpy有一个FFT包来做到这一点。 np.fft.fft2()为我们提供了一个复杂数组的频率变换。
它的第一个参数是输入图像,这是灰度。 第二个参数是可选的,它决定了输出数组的大小。
如果大于输入图像的大小,则输入图像在计算FFT之前用零填充。 如果小于输入图像,输入图像将被裁剪。
如果没有参数传递,输出数组大小将与输入相同。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('messi5.jpg',0)
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)
magnitude_spectrum = 20*np.log(np.abs(fshift))
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()
通过使用大小为60x60的矩形窗口进行屏蔽来简单地移除低频。 然后使用np.fft.ifftshift()应用反向移位,以便DC分量再次出现在左上角。
然后使用np.ifft2()函数找到逆FFT。 结果又是一个复杂的数字。 你可以把它的绝对价值。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('testset/img4.PNG',0)
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)
rows, cols = img.shape
crow,ccol = rows/2 , cols/2
fshift[crow-30:crow+30, ccol-30:ccol+30] = 0
f_ishift = np.fft.ifftshift(fshift)
img_back = np.fft.ifft2(f_ishift)
img_back = np.abs(img_back)
plt.subplot(131),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(132),plt.imshow(img_back, cmap = 'gray')
plt.title('Image after HPF'), plt.xticks([]), plt.yticks([])
plt.subplot(133),plt.imshow(img_back)
plt.title('Result in JET'), plt.xticks([]), plt.yticks([])
plt.show()
opencv中使用傅里叶变化
import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('messi5.jpg',0)
dft = cv2.dft(np.float32(img),flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)
magnitude_spectrum = 20*np.log(cv2.magnitude(dft_shift[:,:,0],dft_shift[:,:,1]))
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()
去除图像中的高频内容,即我们将LPF应用于图像。
它实际上模糊了图像。 为此,我们首先在低频创建一个具有高值(1)的掩码,即我们通过LF内容,在HF区域通过0。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('testset/img4.PNG',0)
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)
rows, cols = img.shape
crow,ccol = rows/2 , cols/2
# create a mask first, center square is 1, remaining all zeros
mask = np.zeros((rows,cols,2),np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 1
dft = cv2.dft(np.float32(img),flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)
# apply mask and inverse DFT
fshift = dft_shift*mask
f_ishift = np.fft.ifftshift(fshift)
img_back = cv2.idft(f_ishift)
img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1])
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(img_back, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()
===========================================模板匹配
#模板匹配是一种在较大图像中搜索和查找模板图像的位置的方法。 为此,OpenCV带有一个函数cv2.matchTemplate()。
它只需将模板图像滑过输入图像(如2D卷积),并比较模板图像下的输入图像的模板和补丁。 OpenCV中实现了几种比较方法。
(您可以查看文档了解更多详情)。 它返回灰度图像,其中每个像素表示该像素的邻域与模板匹配多少。
如果输入图像的大小(WxH)和模板图像的大小(wxh),则输出图像的大小为(W-w + 1,H-h + 1)。
一旦得到结果,您可以使用cv2.minMaxLoc()函数查找最大/最小值的位置。 将其作为矩形的左上角,并将(w,h)作为矩形的宽度和高度。
那个矩形是你的模板区域
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('messi5.jpg',0)
img2 = img.copy()
template = cv2.imread('template.jpg',0)
w, h = template.shape[::-1]
# All the 6 methods for comparison in a list
methods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR',
'cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED']
for meth in methods:
img = img2.copy()
method = eval(meth)
# Apply template Matching
res = cv2.matchTemplate(img,template,method)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
# If the method is TM_SQDIFF or TM_SQDIFF_NORMED, take minimum
if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
top_left = min_loc
else:
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
cv2.rectangle(img,top_left, bottom_right, 255, 2)
plt.subplot(121),plt.imshow(res,cmap = 'gray')
plt.title('Matching Result'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(img,cmap = 'gray')
plt.title('Detected Point'), plt.xticks([]), plt.yticks([])
plt.suptitle(meth)
plt.show()
-------------------------------------模板匹配多个对象
import cv2
import numpy as np
from matplotlib import pyplot as plt
img_rgb = cv2.imread('mario.png')
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread('mario_coin.png',0)
w, h = template.shape[::-1]
res = cv2.matchTemplate(img_gray,template,cv2.TM_CCOEFF_NORMED)
threshold = 0.8
loc = np.where( res >= threshold)
for pt in zip(*loc[::-1]):
cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0,0,255), 2)
cv2.imwrite('res.png',img_rgb)
=============================================霍夫线变换
import cv2
import numpy as np
img = cv2.imread('dave.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray,50,150,apertureSize = 3)
lines = cv2.HoughLines(edges,1,np.pi/180,200)
for rho,theta in lines[0]:
a = np.cos(theta)
b = np.sin(theta)
x0 = a*rho
y0 = b*rho
x1 = int(x0 + 1000*(-b))
y1 = int(y0 + 1000*(a))
x2 = int(x0 - 1000*(-b))
y2 = int(y0 - 1000*(a))
cv2.line(img,(x1,y1),(x2,y2),(0,0,255),2)
cv2.imwrite('houghlines3.jpg',img)
-----------------------------------概率霍夫线变换
import cv2
import numpy as np
img = cv2.imread('dave.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray,50,150,apertureSize = 3)
minLineLength = 100
maxLineGap = 10
lines = cv2.HoughLinesP(edges,1,np.pi/180,100,minLineLength,maxLineGap)
for x1,y1,x2,y2 in lines[0]:
cv2.line(img,(x1,y1),(x2,y2),(0,255,0),2)
cv2.imwrite('houghlines5.jpg',img)
===========================================霍夫圈变换
import cv2
import numpy as np
img = cv2.imread('opencv_logo.png',0)
img = cv2.medianBlur(img,5)
cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)
circles = cv2.HoughCircles(img,cv2.HOUGH_GRADIENT,1,20,
param1=50,param2=30,minRadius=0,maxRadius=0)
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
# draw the outer circle
cv2.circle(cimg,(i[0],i[1]),i[2],(0,255,0),2)
# draw the center of the circle
cv2.circle(cimg,(i[0],i[1]),2,(0,0,255),3)
cv2.imshow('detected circles',cimg)
cv2.waitKey(0)
cv2.destroyAllWindows()
=============================================图像分割分水岭算法
OpenCV实现了一个基于标记的分水岭算法,您可以在其中指定要合并哪些山谷点,哪些不是。它是一种交互式图像分割。
我们所做的是为我们知道的对象给出不同的标签。标记我们确定是具有一种颜色(或强度)的前景或对象的区域,
标记我们确定为背景的区域或具有另一种颜色的非对象的区域,最后标记我们不确定任何内容的区域,标记为0.这是我们的标记。
然后应用分水岭算法。然后我们的标记将使用我们给出的标签更新,对象的边界将具有-1的值。
import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('testset/img4.PNG')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
# noise removal
kernel = np.ones((3,3),np.uint8)
opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel, iterations = 2)
# sure background area
sure_bg = cv2.dilate(opening,kernel,iterations=3)
# Finding sure foreground area
dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5)
ret, sure_fg = cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0)
# Finding unknown region
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg,sure_fg)
# Marker labelling
ret, markers = cv2.connectedComponents(sure_fg)
# Add one to all labels so that sure background is not 0, but 1
markers = markers+1
# Now, mark the region of unknown with zero
markers[unknown==255] = 0
markers = cv2.watershed(img,markers)
img[markers == -1] = [255,0,0]
==================================================使用GrabCut算法进行交互式前景提取
import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('messi5.jpg')
mask = np.zeros(img.shape[:2],np.uint8)
bgdModel = np.zeros((1,65),np.float64)
fgdModel = np.zeros((1,65),np.float64)
rect = (50,50,450,290)
cv2.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT)
mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')
img = img*mask2[:,:,np.newaxis]
plt.imshow(img),plt.colorbar(),plt.show()
在油漆应用程序中打开输入图像,并向图像添加了另一个图层。 在油漆中使用画笔工具,我在这个新图层上用黑色标记了白色和不需要的背景
(如标志,地面等)的未来前景(头发,鞋子,球等)。 然后用灰色填充剩余的背景。 然后在OpenCV中加载该掩码图像,编辑原始掩码图像,
我们在新添加的掩码图像中得到相应的值。 检查以下代码:
# newmask is the mask image I manually labelled
newmask = cv2.imread('newmask.png',0)
# whereever it is marked white (sure foreground), change mask=1
# whereever it is marked black (sure background), change mask=0
mask[newmask == 0] = 0
mask[newmask == 255] = 1
mask, bgdModel, fgdModel = cv2.grabCut(img,mask,None,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_MASK)
mask = np.where((mask==2)|(mask==0),0,1).astype('uint8')
img = img*mask[:,:,np.newaxis]
plt.imshow(img),plt.colorbar(),plt.show()
import cv2
import numpy as np
## opencv 处理 images
# 使用cv2.imread() 读图片
#img=cv2.imread('testset/img4.PNG',-1) #第二个参数为flag :cv2.IMREAD_COLOR,cv2.IMREAD_GRAYSCALE,cv2.IMREAD_UNCHANGED 简记为 1,0,-1
# 1(彩色图像,任何透明图像被忽略,默认值),0:灰度模式 -1:加载图像包含alpha通道
#使用cv2.imshow() 展示图片
#cv2.imshow('image',img) #第一个参数为窗口名是一个字符串,第二个参数是要展示的图像
#cv2.waitKey(0) #键盘绑定功能,参数以毫秒为单位的时间,功能为等待任何键盘时间制定的毫秒,如果0被传递,无限等待一个键盘操作。
#cv2.destroyAllWindows() #破坏我们创建的所哟窗口,如果要销毁特定的窗口使用cv2.destroyWindow()来传递确切窗口名称为参数
#使用cv2.imwrite()保存一个图像
#cv2.imwrite('save.png',img) #第一个参数为保存的文件名,第二个参数为要保存的图像
=====================================================================================================
## opencv 处理 videos
# 从相机捕获并显示
# 要捕获视频,您需要创建一个VideoCapture对象。 其参数可以是设备索引或视频文件的名称。
# 设备索引只是指定哪个相机的号码。 通常一个相机将被连接(如我的情况,使用笔记本电脑的内置网络摄像头)。
# 所以我只是通过0(或-1)。 您可以通过1选择第二台相机,依此类推。 别忘了释放捕获。
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
while(True):
# Capture frame-by-frame
ret, frame = cap.read() # 返回一个bool(True / False)。
# 如果frame正确读取,则为True。 所以你可以通过检查这个返回值来检查视频的结尾。
# 没有初始化捕获。 在这种情况下,此代码显示错误。 您可以通过cap.isOpened()方法检查是否已初始化。
# 如果是True,OK。 否则使用cap.open()打开它。
#还可以使用cap.get(propId)方法访问此视频的某些功能,其中propId是从0到18的数字。每个数字表示视频的属性(如果适用于该视频),
# 并且完整的详细信息可以 在这里可以看到:属性标识符。 这些值中的一些可以使用cap.set(propId,value)进行修改。 价值是你想要的新价值。
#例如,我可以通过cap.get(3)和cap.get(4)来检查框架的宽度和高度。 默认情况下给我640x480。 但是我想将其修改为320x240。
# 只需使用ret = cap.set(3,320)和ret = cap.set(4,240)。
# Our operations on the frame come here
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Display the resulting frame
cv2.imshow('frame',gray)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
===========================================================================================
# 从文件中播放视频
import numpy as np
import cv2
cap = cv2.VideoCapture('baby.mp4')
while(cap.isOpened()):
ret, frame = cap.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imshow('frame',gray)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
===============================================================================
#保存一个视频
#创建一个VideoWriter对象。 我们应该指定输出文件名(例如:output.avi)。
那么我们应该指定FourCC代码。 然后应通过每秒帧数(fps)和帧大小。
最后一个是isColor标志。 如果为True,编码器需要彩色帧,否则可以使用灰度帧。
#FourCC是用于指定视频编解码器的4字节代码。 可用的代码列表可以在fourcc.org中找到。 它依赖于平台。
#在Fedora:DIVX,XVID,MJPG,X264,WMV1,WMV2。 (XVID是更优选的,MJPG产生高画质的视频,X264提供非常小的视频)
#FourCC代码作为MJPG的cv2.VideoWriter_fourcc('M','J','P','G')或cv2.VideoWriter_fourcc(*'MJPG)传递。
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
# Define the codec and create VideoWriter object
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi',fourcc, 20.0, (640,480))
while(cap.isOpened()):
ret, frame = cap.read()
if ret==True:
frame = cv2.flip(frame,0)
# write the flipped frame
out.write(frame)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
break
# Release everything if job is finished
cap.release()
out.release()
cv2.destroyAllWindows()
=======================================================================================
# coding:utf-8
# 学习使用OpenCV绘制不同的几何形状
# cv2.line(), cv2.circle() , cv2.rectangle(), cv2.ellipse(), cv2.putText()
#img:想要绘制形状的图像
#颜色:形状的颜色。 对于BGR,将其作为元组传递,例如:(255, 0, 0)为蓝色。 对于灰度级,只需传递标量值即可。
#厚度:线或圆的厚度等。如果为圆形的封闭图形通过 - 1,则会填充形状。 默认厚度 = 1
#lineType:线路类型,是否为8连接,抗锯齿线路等。默认情况下,它是8连接的。
# cv2.LINE_AA给出了对于曲线看起来不错的反锯齿线。
import numpy as np
import cv2
# Create a black image
img = np.zeros((512,512,3), np.uint8)
# Draw a diagonal blue line with thickness of 5 px
#img = cv2.line(img,(0,0),(511,511),(255,0,0),5)
#Draw a rectangle
#img = cv2.rectangle(img,(384,0),(510,128),(0,255,0),3)
# Draw a circle
#img = cv2.circle(img,(447,63), 63, (0,0,255), -1)
#Draw a ellipse
#img = cv2.ellipse(img,(256,256),(100,50),0,0,180,255,-1)
# draw a polygon
#pts = np.array([[10,5],[20,30],[70,20],[50,10]], np.int32)
#pts = pts.reshape((-1,1,2))
#img = cv2.polylines(img,[pts],True,(0,255,255))
# add text to image
#需要指定:要写入的文本数据
#要放置的位置坐标(即数据开始的左下角)。
#字体类型(支持支持的字体检查cv2.putText()文档)
#字体大小(指定字体大小)
#常规的东西,如颜色,厚度,lineType等。为了更好看,lineType = cv2.LINE_AA是推荐的。
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img,'OpenCV',(10,500), font, 4,(255,255,255),2,cv2.LINE_AA)
cv2.imshow('1',img)
cv2.waitKey(0)
=====================================================================================================
#鼠标作为画笔 将要使用的函数为:cv2.setMouseCallback()
#鼠标回调函数做一件事,它画一个圆,我们双击
import cv2
import numpy as np
# mouse callback function
def draw_circle(event,x,y,flags,param):
if event == cv2.EVENT_LBUTTONDBLCLK:
cv2.circle(img,(x,y),100,(255,0,0),-1)
# Create a black image, a window and bind the function to window
img = np.zeros((512,512,3), np.uint8)
cv2.namedWindow('image')
cv2.setMouseCallback('image',draw_circle)
while(1):
cv2.imshow('image',img)
if cv2.waitKey(20) & 0xFF == 27:
break
cv2.destroyAllWindows()
#我们绘制矩形或圆形(取决于我们选择的模式),通过像Paint应用程序一样拖动鼠标。 所以我们的鼠标回调函数有两个部分,
一个是绘制矩形和其他的画圆。 这个具体的例子将有助于创建和理解一些交互式应用程序,如对象跟踪,图像分割等。
import cv2
import numpy as np
drawing = False # true if mouse is pressed
mode = True # if True, draw rectangle. Press 'm' to toggle to curve
ix,iy = -1,-1
# mouse callback function
def draw_circle(event,x,y,flags,param):
global ix,iy,drawing,mode
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
ix,iy = x,y
elif event == cv2.EVENT_MOUSEMOVE:
if drawing == True:
if mode == True:
cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),-1)
else:
cv2.circle(img,(x,y),5,(0,0,255),-1)
elif event == cv2.EVENT_LBUTTONUP:
drawing = False
if mode == True:
cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),-1)
else:
cv2.circle(img,(x,y),5,(0,0,255),-1)
img = np.zeros((512,512,3), np.uint8)
cv2.namedWindow('image')
cv2.setMouseCallback('image',draw_circle)
while(1):
cv2.imshow('image',img)
k = cv2.waitKey(1) & 0xFF
if k == ord('m'):
mode = not mode
elif k == 27:
break
cv2.destroyAllWindows()
================================================================================================================
#轨道栏作为调色板
#有一个窗口,显示颜色和三个轨道,以指定B,G,R颜色中的每一个。您滑动轨迹栏和相应的窗口颜色更改。默认情况下,初始颜色将设置为黑色。
#对于cv2.getTrackbarPos()函数,第一个参数是跟踪栏名称,第二个参数是其附加的窗口名称,第三个参数是默认值,第四个参数是最大值,
第五个是执行的回调函数每次跟踪栏值都会发生变化。回调函数始终具有默认参数,即跟踪栏位置。在我们的例子中,函数什么都不做,所以我们简单地通过。
#轨道栏的另一个重要应用是将其用作按钮或开关。默认情况下,OpenCV没有按钮功能。所以你可以使用trackbar获得这样的功能。
#在我们的应用程序中,我们已经创建了一个开关,其中应用程序仅在开关为ON时工作,否则屏幕始终为黑色。
import cv2
import numpy as np
def nothing(x):
pass
# Create a black image, a window
img = np.zeros((300,512,3), np.uint8)
cv2.namedWindow('image')
# create trackbars for color change
cv2.createTrackbar('R','image',0,255,nothing)
cv2.createTrackbar('G','image',0,255,nothing)
cv2.createTrackbar('B','image',0,255,nothing)
# create switch for ON/OFF functionality
switch = '0 : OFF \n1 : ON'
cv2.createTrackbar(switch, 'image',0,1,nothing)
while(1):
cv2.imshow('image',img)
k = cv2.waitKey(1) & 0xFF
if k == 27:
break
# get current positions of four trackbars
r = cv2.getTrackbarPos('R','image')
g = cv2.getTrackbarPos('G','image')
b = cv2.getTrackbarPos('B','image')
s = cv2.getTrackbarPos(switch,'image')
if s == 0:
img[:] = 0
else:
img[:] = [b,g,r]
cv2.destroyAllWindows()
==============================================================================================
=======================================Core Operations========================================
# 访问或修改像素值
import cv2
import numpy as np
img=cv2.imread('testset/img4.PNG')
#通过其行和列坐标访问像素值。
# 对于BGR图像,它返回一个蓝色,绿色,红色值的数组。
# 对于灰度图像,只需返回相应的强度。
#px=img[100,100]
#print px
#108 109 123
#blue=img[100,100,0]
#print blue
#img[100,100]=[255,255,255]
#print img[100,100]
#访问红值
#print img.item(10,10,2)
# 修改红值
#img.itemset((10,10,2),100)
#img.item(10,10,2)
=======================================访问图片属性============================================
import cv2
import numpy as np
img=cv2.imread('testset/img4.PNG')
print img.shape
print img.size
print img.dtype
=======================================分割和合并图像通道======================================
#当需要时,图像的B,G,R通道可以分成各自的平面。 然后,可以将各个频道合并在一起,再次形成BGR图像
import cv2
import numpy as np
img=cv2.imread('testset/img4.PNG')
b,g,r=cv2.split(img)
img=cv2.merge((b,g,r))
===============================图像周围创建边框=================================================
在图像周围创建边框,像相框,可以使用cv2.copyMakeBorder()函数。但是它具有更多的卷积运算,零填充等应用。此功能有以下参数:
src - 输入图像
顶部,底部,左侧,右侧边框宽度,相应方向上的像素数
borderType - 标记要添加的边框类型。它可以是以下类型:
cv2.BORDER_CONSTANT - 添加一个常量的彩色边框。该值应该作为下一个参数给出。
cv2.BORDER_REFLECT - 边框将镜像反射边框元素,如下所示:fedcba | abcdefgh | hgfedcb
cv2.BORDER_REFLECT_101或cv2.BORDER_DEFAULT - 与上述相同,但略有更改,如下所示:gfedcb | abcdefgh | gfedcba
cv2.BORDER_REPLICATE - 最后一个元素全部复制,如下所示:aaaaaa | abcdefgh | hhhhhhhh
cv2.BORDER_WRAP - 无法解释,将如下所示:cdefgh | abcdefgh | abcdefg
value - 如果边框类型为cv2.BORDER_CONSTANT,则为边框颜色
举例来说:
import cv2
import numpy as np
from matplotlib import pyplot as plt
BLUE = [255,0,0]
img1 = cv2.imread('opencv_logo.png')
replicate = cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_REPLICATE)
reflect = cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_REFLECT)
reflect101 = cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_REFLECT_101)
wrap = cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_WRAP)
constant= cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_CONSTANT,value=BLUE)
plt.subplot(231),plt.imshow(img1,'gray'),plt.title('ORIGINAL')
plt.subplot(232),plt.imshow(replicate,'gray'),plt.title('REPLICATE')
plt.subplot(233),plt.imshow(reflect,'gray'),plt.title('REFLECT')
plt.subplot(234),plt.imshow(reflect101,'gray'),plt.title('REFLECT_101')
plt.subplot(235),plt.imshow(wrap,'gray'),plt.title('WRAP')
plt.subplot(236),plt.imshow(constant,'gray'),plt.title('CONSTANT')
plt.show()
===============================图像算术运算========================================
#OpenCV添加和Numpy添加之间有区别。 OpenCV加法是饱和操作,而Numpy加法是模运算。
x = np.uint8([250])
y = np.uint8([10])
print cv2.add(x,y) # 250+10 = 260 => 255
[[255]]
print x+y # 250+10 = 260 % 256 = 4
[4]
===============================图像混合=============================================
#给图像赋予不同的权重,使得它具有混合或透明的感觉,g(x) = (1 - \alpha)f_{0}(x) + \alpha f_{1}(x)
img1 = cv2.imread('ml.png')
img2 = cv2.imread('opencv_logo.jpg')
dst = cv2.addWeighted(img1,0.7,img2,0.3,0)
cv2.imshow('dst',dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
===============================按位操作==============================================
#把OpenCV标志放在图像之上。 如果我添加两个图像,它将改变颜色。 如果我混合,我会得到一个透明的效果。
#但我希望它是不透明的。 如果是一个矩形区域,我可以像上一章那样使用ROI。 但OpenCV标志不是一个矩形。
#所以你可以按照以下的按位操作来做:
# Load two images
img1 = cv2.imread('messi5.jpg')
img2 = cv2.imread('opencv_logo.png')
# 我想把徽标放在左上角,所以我创建了一个ROI
rows,cols,channels = img2.shape
roi = img1[0:rows, 0:cols ]
# 现在创建一个徽标的掩码,并创建它的反掩码
img2gray = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(img2gray, 10, 255, cv2.THRESH_BINARY)
mask_inv = cv2.bitwise_not(mask)
# Now black-out the area of logo in ROI
img1_bg = cv2.bitwise_and(roi,roi,mask = mask_inv)
# 从标志图像中只取标识区域。
img2_fg = cv2.bitwise_and(img2,img2,mask = mask)
# Put logo in ROI 修改主图
dst = cv2.add(img1_bg,img2_fg)
img1[0:rows, 0:cols ] = dst
cv2.imshow('res',img1)
cv2.waitKey(0)
cv2.destroyAllWindows()
=====================================性能测量与改进技术=================================
cv2.getTickCount函数返回参考事件之后的时钟周期数(如机器开机时)到调用此函数的时刻。
因此,如果在函数执行之前和之后调用它,您将获得用于执行函数的时钟周期数。
cv2.getTickFrequency函数返回时钟周期的频率或每秒的时钟周期数。 所以要在几秒钟内找到执行的时间,
你可以做以下操作:
e1 = cv2.getTickCount()
# your code execution
e2 = cv2.getTickCount()
time = (e2 - e1)/ cv2.getTickFrequency()
-----------------------------------------------------------------------------------------
img1 = cv2.imread('messi5.jpg')
e1 = cv2.getTickCount()
for i in xrange(5,49,2):
img1 = cv2.medianBlur(img1,i)#中值滤波
e2 = cv2.getTickCount()
t = (e2 - e1)/cv2.getTickFrequency()
print t
# Result I got is 0.521107655 seconds
==========================================================================================
===================================利用opencv处理图像=====================================
=====================改变颜色=============================================================
BGR-------->Gray,BGR-------------->HSV
#对于颜色转换,我们使用函数cv2.cvtColor(input_image,flag),其中flag决定转换的类型。
对于BGR --灰色转换,我们使用标志cv2.COLOR_BGR2GRAY。 类似地,对于BGR -- HSV,
我们使用标志cv2.COLOR_BGR2HSV。 要获得其他标志,只需在Python终端中运行以下命令:
>>> import cv2
>>> flags = [i for i in dir(cv2) if i.startswith('COLOR_')]
>>> print flags
=============================对象跟踪=====================================================
#拍摄视频的每一帧
#从BGR转换为HSV色彩空间
#我们为一系列蓝色阈值HSV图像
#现在单独提取蓝色对象
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
while(1):
# Take each frame
_, frame = cap.read()
# Convert BGR to HSV
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# define range of blue color in HSV
lower_blue = np.array([110,50,50])
upper_blue = np.array([130,255,255])
# Threshold the HSV image to get only blue colors
mask = cv2.inRange(hsv, lower_blue, upper_blue)
# Bitwise-AND mask and original image
res = cv2.bitwise_and(frame,frame, mask= mask)
cv2.imshow('frame',frame)
cv2.imshow('mask',mask)
cv2.imshow('res',res)
k = cv2.waitKey(5) & 0xFF
if k == 27:
break
cv2.destroyAllWindows()
=================================图像的几何变换======================================
#OpenCV提供了两个转换函数cv2.warpAffine和cv2.warpPerspective,您可以使用它们进行各种转换。
#cv2.warpAffine需要一个2x3变换矩阵,而cv2.warpPerspective则需要一个3x3的变换矩阵作为输入。
#缩放只是调整图像大小。 为此,OpenCV带有一个函数cv2.resize()。
#可以手动指定图像的大小,也可以指定缩放因子。 使用不同的插值方法。
#优选的插值方法是缩小的cv2.INTER_AREA和用于缩放的cv2.INTER_CUBIC(slow)&cv2.INTER_LINEAR。
#默认情况下,使用的插值方法是cv2.INTER_LINEAR,用于所有调整大小的目的。
您可以使用以下方法之一调整输入图像的大小:
import cv2
import numpy as np
img = cv2.imread('messi5.jpg')
res = cv2.resize(img,None,fx=2, fy=2, interpolation = cv2.INTER_CUBIC)
#OR
height, width = img.shape[:2]
res = cv2.resize(img,(2*width, 2*height), interpolation = cv2.INTER_CUBIC)
-------------------------------------翻译-------------------
#cv2.warpAffine()函数的第三个参数是输出图像的大小,它应该是(width,height)的形式。
#记住width =列数,height =行数。
import cv2
import numpy as np
img = cv2.imread('messi5.jpg',0)
rows,cols = img.shape
M = np.float32([[1,0,100],[0,1,50]])
dst = cv2.warpAffine(img,M,(cols,rows))
cv2.imshow('img',dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
---------------------------------------旋转--------------------------------
img = cv2.imread('messi5.jpg',0)
rows,cols = img.shape
M = cv2.getRotationMatrix2D((cols/2,rows/2),90,1)#旋转90度
dst = cv2.warpAffine(img,M,(cols,rows))
-------------------------------------仿射变换------------------------------------------
#在仿射变换中,原始图像中的所有平行线在输出图像中仍然是平行的。 为了找到转换矩阵,
#我们需要输入图像中的三个点和输出图像中相应的位置。 然后cv2.getAffineTransform将创建一个2x3矩阵,
#传递给cv2.warpAffine。
img = cv2.imread('drawing.png')
rows,cols,ch = img.shape
pts1 = np.float32([[50,50],[200,50],[50,200]])
pts2 = np.float32([[10,100],[200,50],[100,250]])
M = cv2.getAffineTransform(pts1,pts2)
dst = cv2.warpAffine(img,M,(cols,rows))
plt.subplot(121),plt.imshow(img),plt.title('Input')
plt.subplot(122),plt.imshow(dst),plt.title('Output')
plt.show()
-------------------------------------透视转换---------------------------------------------
#对于透视变换,您需要一个3x3变换矩阵。 即使转型后,直线也保持直线。
#要找到此转换矩阵,您需要输入图像上的4点和输出图像上的对应点。 在这4个点中,其中3个不应该共线。
#那么转换矩阵可以通过函数cv2.getPerspectiveTransform找到。
#然后用这个3x3转换矩阵应用cv2.warpPerspective。
img = cv2.imread('sudokusmall.png')
rows,cols,ch = img.shape
pts1 = np.float32([[56,65],[368,52],[28,387],[389,390]])
pts2 = np.float32([[0,0],[300,0],[0,300],[300,300]])
M = cv2.getPerspectiveTransform(pts1,pts2)
dst = cv2.warpPerspective(img,M,(300,300))
plt.subplot(121),plt.imshow(img),plt.title('Input')
plt.subplot(122),plt.imshow(dst),plt.title('Output')
plt.show()
====================================图像阈值=====================================================
#如果像素值大于阈值,则分配一个值(可以是白色),否则分配另一个值(可以是黑色)。 所使用的函数是cv2.threshold。
# 第一个参数是源图像,它应该是灰度图像。 第二个参数是用于对像素值进行分类的阈值。
# 第三个参数是maxVal,它表示如果像素值大于(有时小于)阈值时给出的值。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('gradient.png',0)
ret,thresh1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
ret,thresh2 = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV)
ret,thresh3 = cv2.threshold(img,127,255,cv2.THRESH_TRUNC)
ret,thresh4 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO)
ret,thresh5 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO_INV)
titles = ['Original Image','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]
for i in xrange(6):
plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
=============================自适应阈值===============================================================
#该算法计算图像的小区域的阈值。 所以我们得到不同的相同图像区域的不同的阈值,它给我们更好的结果,对于具有不同照明的图像。
它有三个“特殊”输入参数,只有一个输出参数。
自适应方法 - 它决定如何计算阈值值。
cv2.ADAPTIVE_THRESH_MEAN_C:阈值是邻域的平均值。
cv2.ADAPTIVE_THRESH_GAUSSIAN_C:阈值是权重是高斯窗口的邻域值的加权和。
块大小 - 它决定邻域的大小。
C - 它只是一个常数,它从平均值或加权平均值中减去。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('dave.jpg',0)
img = cv2.medianBlur(img,5)
ret,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
th2 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,\
cv2.THRESH_BINARY,11,2)
th3 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
cv2.THRESH_BINARY,11,2)
titles = ['Original Image', 'Global Thresholding (v = 127)',
'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
images = [img, th1, th2, th3]
for i in xrange(4):
plt.subplot(2,2,i+1),plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
=================================二值化===================================================================
#我们使用cv2.threshold()函数,但通过额外的标志cv2.THRESH_OTSU。对于阈值,只需通过零。
#然后,算法找到最佳阈值,并返回您作为第二个输出retVal。
#如果不使用Otsu阈值,retVal与您使用的阈值相同。
#查看下面的例子。输入图像是嘈杂的图像。在第一种情况下,我应用了全局阈值为127的值。
#在第二种情况下,我直接应用了大津的阈值。在第三种情况下,我用5x5高斯内核过滤图像以去除噪声,然后应用Otsu阈值。
#了解噪声过滤如何改善结果。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('noisy2.png',0)
# global thresholding
ret1,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
# Otsu's thresholding
ret2,th2 = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# Otsu's thresholding after Gaussian filtering
blur = cv2.GaussianBlur(img,(5,5),0)
ret3,th3 = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# plot all the images and their histograms
images = [img, 0, th1,
img, 0, th2,
blur, 0, th3]
titles = ['Original Noisy Image','Histogram','Global Thresholding (v=127)',
'Original Noisy Image','Histogram',"Otsu's Thresholding",
'Gaussian filtered Image','Histogram',"Otsu's Thresholding"]
for i in xrange(3):
plt.subplot(3,3,i*3+1),plt.imshow(images[i*3],'gray')
plt.title(titles[i*3]), plt.xticks([]), plt.yticks([])
plt.subplot(3,3,i*3+2),plt.hist(images[i*3].ravel(),256)
plt.title(titles[i*3+1]), plt.xticks([]), plt.yticks([])
plt.subplot(3,3,i*3+3),plt.imshow(images[i*3+2],'gray')
plt.title(titles[i*3+2]), plt.xticks([]), plt.yticks([])
plt.show()
======================================平滑图像=================================================
#二维卷积(图像过滤)
对于一维信号,图像也可以通过各种低通滤波器(LPF),高通滤波器(HPF)等进行滤波.LFF有助于消除噪声或模糊图像。
HPF滤镜有助于在图像中找到边。
OpenCV提供了一个函数cv2.filter2D()来将内核与图像进行卷积。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('opencv_logo.png')
kernel = np.ones((5,5),np.float32)/25#5x5卷积,平均滤波
dst = cv2.filter2D(img,-1,kernel)
plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(dst),plt.title('Averaging')
plt.xticks([]), plt.yticks([])
plt.show()
=====================================图像模糊(图像平滑)=======================================
图像模糊是通过使用低通滤波器内核卷积图像来实现的。 它有助于消除噪音。
它实际上从图像中去除了高频内容(例如,噪点,边缘),导致当应用滤镜时边缘被模糊。
(嗯,有模糊的技术,不模糊边缘)。
OpenCV主要提供四种模糊技术。
平均
这是通过用标准化的盒式滤波器卷积图像来完成的。 它只需要将内核区域下的所有像素的平均值取代为该平均值的中心元素。
这由函数cv2.blur()或cv2.boxFilter()完成。 如果不想使用标准化的框过滤器,请使用cv2.boxFilter()并将参数normalize = False传递给函数。
我们应该指定内核的宽度和高度。 3x3标准化的盒式过滤器将如下所示:
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('opencv_logo.png')
blur = cv2.blur(img,(5,5))
plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(blur),plt.title('Blurred')
plt.xticks([]), plt.yticks([])
plt.show()
高斯滤波
在这种方法中,代替由相等的滤波器系数组成的盒式滤波器,使用高斯核。 它使用函数cv2.GaussianBlur()完成。
我们应该指定内核的宽度和高度,它应该是正的和奇数的。 我们还应该分别指定X和Y方向的标准差,sigmaX和sigmaY。
如果仅指定sigmaX,则将σigma取为等于sigmaX。 如果两者均为零,则从内核大小计算。
高斯滤波在去除图像中的高斯噪声方面非常有效。
如果需要,可以使用函数cv2.getGaussianKernel()创建一个高斯内核。
上述代码可以修改为高斯模糊:
blur = cv2.GaussianBlur(img,(5,5),0)
中值滤波
这里,函数cv2.medianBlur()计算内核窗口下的所有像素的中值,中心像素被替换为该中值。
这对消除噪音非常有效。 要注意的一个有趣的事情是,在高斯和滤波器中,中心元素的滤波值可以是原始图像中可能不存在的值。
然而,中值滤波并不是这样,因为中心元素总是被图像中的某些像素值替代。 这有效地降低了噪音。 内核大小必须是正的奇整数。
在这个演示中,我们给原始图像增加了50%的噪声,并使用了中值滤波器。 检查结果:
median = cv2.medianBlur(img,5)
双边过滤
我们之前呈现的滤镜往往会模糊边缘。双向滤波器cv2.bilateralFilter()不是这种情况,cv2.bilateralFilter()被定义为,
并且在保留边缘的同时非常有效地进行噪声去除。但与其他过滤器相比,操作较慢。我们已经看到,高斯滤波器在像素周围附近找到一个邻域,
并找到其高斯加权平均值。这个高斯滤波器是单独的空间的函数,也就是在滤波时考虑附近的像素。不考虑像素是否具有几乎相同的强度值,
并且不考虑像素是否位于边缘上。所产生的效果是高斯滤波器倾向于模糊边缘,这是不期望的。
双边滤波器还在空间域中使用高斯滤波器,但它也使用一个(乘法)高斯滤波器分量,它是像素强度差异的函数。
空间的高斯函数确保只有像素是“空间相邻”被用于滤波,而在强度域中应用的高斯分量(强度差的高斯函数)
确保仅具有与中心的强度相似的像素包含像素(“强度邻居”)以计算模糊强度值。结果,该方法保留边缘,
因为对于位于边缘附近的像素,相对于边缘的相邻像素,并且因此与中心像素相比表现出大的强度变化,将不包括模糊。
下面的示例演示了双边过滤的使用
blur = cv2.bilateralFilter(img,9,75,75)
==========================================形态转化=================================================
-----------------------------------------腐蚀------------------------------------------
侵蚀
侵蚀的基本思想就像只有土壤侵蚀,它侵蚀了前景物体的边界(总是尽量保持前景白色)。 那么它是做什么的呢? 内核滑过图像(如2D卷积)。
只有当内核下的所有像素为1时,才能将原始图像(1或0)中的像素视为1,否则将被侵蚀(使为零)。
所以发生的是,边界附近的所有像素将被丢弃,这取决于内核的大小。 因此,前景对象的厚度或尺寸减小,或者仅仅是图像中的白色区域减小。
它有助于去除小白噪声(如我们在颜色空间章节中看到的),分离两个连接的对象等。
import cv2
import numpy as np
img = cv2.imread('j.png',0)
kernel = np.ones((5,5),np.uint8)
erosion = cv2.erode(img,kernel,iterations = 1)
cv2.imshow('erosion',img)
cv2.waitKey(0)
----------------------------------------膨胀----------------------------------------------
#扩张
正好与侵蚀相反。 这里,如果内核下至少有一个像素为“1”,像素元素为“1”。 所以它增加了图像中的白色区域或前景对象的大小增加。
通常,在噪声消除的情况下,侵蚀之后是扩张。 因为侵蚀消除了白色的噪音,而且也缩小了我们的对象。 所以我们扩大它。
由于噪音消失,他们不会回来,但我们的对象面积增加。 它也可用于连接物体的断裂部分。
dilation = cv2.dilate(img,kernel,iterations = 1)
---------------------------------------开放-----------------------------------------------
开放
开放只是另一个侵蚀的名字,随后是扩张。 如上所述,它有助于消除噪音。 这里我们使用函数cv2.morphologyEx()
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
---------------------------------------关闭-----------------------------------------------
关闭
封闭与开放相反,扩张之后是侵蚀。 关闭前景物体中的小孔或物体上的小黑点是有用的。
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
---------------------------------------形态梯度----------------------------------------------
这是图像的扩张和侵蚀的区别。结果将看起来像对象的轮廓。
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
--------------------------------------顶帽------------------------------------------------------
它是输入图像和图像打开之间的区别。 下面的例子是为一个9x9内核完成的
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
----------------------------------------黑帽------------------------------------------------
输入图像和输入图像的关闭是不同的。
blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
---------------------------------------结构元素----------------------------------------------
在Numpy的帮助下,我们在前面的例子中手动创建了一个结构化元素。 它是矩形的。 但是在某些情况下,您可能需要椭圆/圆形的内核。
所以为了这个目的,OpenCV有一个函数cv2.getStructuringElement()。 你只是传递内核的形状和大小,你会得到所需的内核。
cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5))
================================================图像渐变========================================================
OpenCV提供三种类型的梯度滤波器或高通滤波器,Sobel,Scharr和Laplacian。
Sobel和Scharr衍生物
Sobel操作员是高斯平滑加分散操作的联合,因此更能抵抗噪音。 您可以指定要采取的导数的方向,垂直方向或水平方向(分别为参数yorder和xorder)。
您还可以通过参数ksize指定内核的大小。 如果ksize = -1,则使用3x3 Scharr滤波器,该滤波器比3x3 Sobel滤波器更好的结果。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('dave.jpg',0)
laplacian = cv2.Laplacian(img,cv2.CV_64F)
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=5)
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=5)
plt.subplot(2,2,1),plt.imshow(img,cmap = 'gray')
plt.title('Original'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,2),plt.imshow(laplacian,cmap = 'gray')
plt.title('Laplacian'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,3),plt.imshow(sobelx,cmap = 'gray')
plt.title('Sobel X'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,4),plt.imshow(sobely,cmap = 'gray')
plt.title('Sobel Y'), plt.xticks([]), plt.yticks([])
plt.show()
------------------
将黑白转换作为正斜率(它具有正值),而将白 - 黑转换作为负斜率(它具有负值)。
所以当你将数据转换为np.uint8时,所有的负斜率均为零。 简单来说,你错过了这个边缘。
如果要检测到这两个边,更好的选择是将输出数据类型保持为一些较高的形式,如cv2.CV_16S,cv2.CV_64F等,取其绝对值,然后转换回cv2.CV_8U。
下面的代码演示了水平Sobel滤波器的这个过程以及结果的差异。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('box.png',0)
# Output dtype = cv2.CV_8U
sobelx8u = cv2.Sobel(img,cv2.CV_8U,1,0,ksize=5)
# Output dtype = cv2.CV_64F. Then take its absolute and convert to cv2.CV_8U
sobelx64f = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=5)
abs_sobel64f = np.absolute(sobelx64f)
sobel_8u = np.uint8(abs_sobel64f)
plt.subplot(1,3,1),plt.imshow(img,cmap = 'gray')
plt.title('Original'), plt.xticks([]), plt.yticks([])
plt.subplot(1,3,2),plt.imshow(sobelx8u,cmap = 'gray')
plt.title('Sobel CV_8U'), plt.xticks([]), plt.yticks([])
plt.subplot(1,3,3),plt.imshow(sobel_8u,cmap = 'gray')
plt.title('Sobel abs(CV_64F)'), plt.xticks([]), plt.yticks([])
plt.show()
====================================================canny 边缘检测=================================================
#OpenCV将以上所有内容放在单个函数cv2.Canny()中。 我们将看到如何使用它。 第一个参数是我们的输入图像。 第二和第三个参数分别是我们的minVal和maxVal。
#第三个参数是aperture_size。 用于查找图像渐变的Sobel内核的大小。 默认情况下是3。最后一个参数是L2gradient,它指定查找梯度大小的方程。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('messi5.jpg',0)
edges = cv2.Canny(img,100,200)
plt.subplot(121),plt.imshow(img,cmap = 'gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(edges,cmap = 'gray')
plt.title('Edge Image'), plt.xticks([]), plt.yticks([])
plt.show()
====================================================图像金字塔=======================================================
#我们需要处理相同图像的不同分辨率的图像。例如,在像图像中寻找某物的同时,我们不确定图像中的对象将以什么大小显示。
在这种情况下,我们将需要创建一组不同分辨率的图像,并在所有图像中搜索对象。
这些具有不同分辨率的图像被称为图像金字塔(因为当它们保持在堆叠中,最大图像在底部,最小图像在顶部看起来像金字塔)。
有两种图像金字塔。 1)高斯金字塔和2)拉普拉斯金字塔
高斯金字塔中的较高级别(低分辨率)是通过删除较低级别(较高分辨率)图像中的连续行和列来形成的。
然后,较高级别中的每个像素由基础级别中的5个像素与高斯权重的贡献形成。通过这样做,M \ times N图像成为M / 2 \次N / 2图像。
因此,面积减少到原始面积的四分之一。它被称为八度。我们在金字塔上升(即分辨率降低)时,相同的模式继续下去。
类似地,在扩展时,每个层面的面积变成4倍。我们可以使用cv2.pyrDown()和cv2.pyrUp()函数找到高斯金字塔。
img = cv2.imread('messi5.jpg')
lower_reso = cv2.pyrDown(higher_reso)
higher_reso2 = cv2.pyrUp(lower_reso)
----------------------------------------------使用金字塔的图像混合--------------------------------------------------
#金字塔的一个应用是图像混合。 例如,在图像拼接中,您需要将两个图像堆叠在一起,但由于图像之间的不连续性,它可能看起来不太好。
在这种情况下,与金字塔的图像混合可以让您无缝混合,而不会在图像中留下大量数据。 一个典型的例子就是混合了两种水果,橙子和苹果。
现在看看结果来了解我在说什么:
import cv2
import numpy as np,sys
A = cv2.imread('apple.jpg')
B = cv2.imread('orange.jpg')
# generate Gaussian pyramid for A
G = A.copy()
gpA = [G]
for i in xrange(6):
G = cv2.pyrDown(G)
gpA.append(G)
# generate Gaussian pyramid for B
G = B.copy()
gpB = [G]
for i in xrange(6):
G = cv2.pyrDown(G)
gpB.append(G)
# generate Laplacian Pyramid for A
lpA = [gpA[5]]
for i in xrange(5,0,-1):
GE = cv2.pyrUp(gpA[i])
L = cv2.subtract(gpA[i-1],GE)
lpA.append(L)
# generate Laplacian Pyramid for B
lpB = [gpB[5]]
for i in xrange(5,0,-1):
GE = cv2.pyrUp(gpB[i])
L = cv2.subtract(gpB[i-1],GE)
lpB.append(L)
# Now add left and right halves of images in each level
LS = []
for la,lb in zip(lpA,lpB):
rows,cols,dpt = la.shape
ls = np.hstack((la[:,0:cols/2], lb[:,cols/2:]))
LS.append(ls)
# now reconstruct
ls_ = LS[0]
for i in xrange(1,6):
ls_ = cv2.pyrUp(ls_)
ls_ = cv2.add(ls_, LS[i])
# image with direct connecting each half
real = np.hstack((A[:,:cols/2],B[:,cols/2:]))
cv2.imwrite('Pyramid_blending2.jpg',ls_)
cv2.imwrite('Direct_blending.jpg',real)
==============================================opencv中的轮廓=============================================================
#轮廓可以简单地解释为连接所有连续点(沿着边界),具有相同颜色或强度的曲线。 轮廓是形状分析和物体检测和识别的有用工具。
为了更好的准确性,使用二进制图像 所以在找到轮廓之前,应用阈值或边缘检测。
findContours函数修改源图像。 所以如果你想要源图像,即使在找到轮廓之后,已经存储到一些其他的变量。
在OpenCV中,查找轮廓就像从黑色背景中找到白色物体。 所以记住,要找到的对象应该是白色的,背景应该是黑色的。
让我们看看如何找到二进制图像的轮廓:
--------------------------------------------------------------------------------------------------------------------------
要绘制轮廓,使用cv2.drawContours函数。 它也可以用来绘制任何形状,只要你有它的边界点。 它的第一个参数是源图像,
第二个参数是应该作为Python列表传递的轮廓,第三个参数是轮廓的索引(在绘制单个轮廓时有用)绘制所有轮廓,传递-1),
剩余的参数是颜色,厚度 等等
绘制图像中的所有轮廓:
img = cv2.drawContours(img,轮廓,-1,(0,255,0),3)
绘制个别轮廓,说第4轮廓:
img = cv2.drawContours(img,轮廓,3,(0,255,0),3)
但大多数时候,下面的方法将是有用的:
cnt =轮廓[4]
img = cv2.drawContours(img,[cnt],0,(0,255,0),3)
----------------------------------------------------------------------------------------------------------------------------
import cv2
im = cv2.imread('testset/img4.PNG')
imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray,127,255,0)
image, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
img = cv2.drawContours(image, contours, -1, (0,255,0), 3)
#2 img = cv2.drawContours(image, contours, 3, (0,255,0), 3)
#3 cnt = contours[4]
#3 img = cv2.drawContours(image, [cnt], 0, (0,255,0), 3)
cv2.imshow('as',img)
cv2.waitKey(0)
---------------------------------------------------轮廓特征-------------------------------------------------------------------
---------------------------------------------图像时刻
import cv2
import numpy as np
img = cv2.imread('star.jpg',0)
ret,thresh = cv2.threshold(img,127,255,0)
contours,hierarchy = cv2.findContours(thresh, 1, 2)
cnt = contours[0]
M = cv2.moments(cnt)
print M
---------------------------------------------图像轮廓
area = cv2.contourArea(cnt)
---------------------------------------------图像周长
perimeter = cv2.arcLength(cnt,True)
---------------------------------------------图像近似
假设您正在尝试在图像中找到一个正方形,但是由于图像中存在一些问题,您没有获得一个完美的方形,而是一个“坏的形状”(如下图所示)。
现在您可以使用此功能近似形状。 在这里,第二个参数称为epsilon,它是从轮廓到近似轮廓的最大距离。 这是一个精度参数。
需要一个明智的选择来获得正确的输出。
epsilon = 0.1*cv2.arcLength(cnt,True)
approx = cv2.approxPolyDP(cnt,epsilon,True)
---------------------------------------------凸包
看起来类似于轮廓近似,但它不是(两者可能在某些情况下提供相同的结果)。 这里,cv2.convexHull()函数检查一个曲线的凸性缺陷并进行修正。
一般来说,凸曲线是总是凸出的或至少平坦的曲线。 如果内部膨胀,则称为凸面缺陷。
hull = cv2.convexHull(points[, hull[, clockwise[, returnPoints]]
Arguments details:
points are the contours we pass into.
hull is the output, normally we avoid it.
clockwise : Orientation flag. If it is True, the output convex hull is oriented clockwise.
Otherwise, it is oriented counter-clockwise.
returnPoints : By default, True. Then it returns the coordinates of the hull points.
If False, it returns the indices of contour points corresponding to the hull points.
hull = cv2.convexHull(cnt)
但是如果要查找凸性缺陷,则需要传递returnPoints = False。要理解它,我们将把上面的矩形图像。首先我发现它的轮廓为cnt。
现在我发现它的凸包具有returnPoints = True,我得到以下值:[[[234 202]],[[51 202]],[[51 79]],[[234 79]]]矩形点。
现在如果对returnPoints = False做同样的,我得到以下结果:[[129],[67],[0],[142]]。这些是轮廓中相应点的指标。
例如,检查与第一个结果相同的第一个值:cnt [129] = [[234,202]](对于其他结果,等等)。
-------------------------------------------旋转矩形
以最小面积绘制边界矩形,因此也考虑旋转。 使用的功能是cv2.minAreaRect()。 它返回一个Box2D结构,其包含以下detals - (左上角(x,y),(宽度,高度),旋转角度)。
但是要绘制这个矩形,我们需要矩形的四个角。 它是通过函数cv2.boxPoints()获得的
rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
box = np.int0(box)
im = cv2.drawContours(im,[box],0,(0,0,255),2)
-------------------------------------------最小封闭圆圈
#我们使用函数cv2.minEnclosingCircle()找到对象的外接圆。 它是一个圆形,完全覆盖最小面积的物体。
(x,y),radius = cv2.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
img = cv2.circle(img,center,radius,(0,255,0),2)
-------------------------------------------拟合的椭圆
将一个椭圆适合于一个对象。 它返回旋转的矩形,其中刻有椭圆。
ellipse = cv2.fitEllipse(cnt)
im = cv2.ellipse(im,ellipse,(0,255,0),2)
-------------------------------------------直线拟合
我们可以将一条线适合一组点。 图像下方包含一组白点。 我们可以近似一条直线。
rows,cols = img.shape[:2]
[vx,vy,x,y] = cv2.fitLine(cnt, cv2.DIST_L2,0,0.01,0.01)
lefty = int((-x*vy/vx) + y)
righty = int(((cols-x)*vy/vx)+y)
img = cv2.line(img,(cols-1,righty),(0,lefty),(0,255,0),2)
------------------------------------------轮廓属性
---------------------长宽比
x,y,w,h = cv2.boundingRect(cnt)
aspect_ratio = float(w)/h
---------------------幅度
area = cv2.contourArea(cnt)
x,y,w,h = cv2.boundingRect(cnt)
rect_area = w*h
extent = float(area)/rect_area
---------------------密实度
area = cv2.contourArea(cnt)
hull = cv2.convexHull(cnt)
hull_area = cv2.contourArea(hull)
solidity = float(area)/hull_area
--------------------等效直径
area = cv2.contourArea(cnt)
equi_diameter = np.sqrt(4*area/np.pi)
--------------------方向
(x,y),(MA,ma),angle = cv2.fitEllipse(cnt)
--------------------面具和像素点
mask = np.zeros(imgray.shape,np.uint8)
cv2.drawContours(mask,[cnt],0,255,-1)
pixelpoints = np.transpose(np.nonzero(mask))
#pixelpoints = cv2.findNonZero(mask)
--------------------最大值,最小值及其位置
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(imgray,mask = mask)
--------------------平均颜色或平均强度
mean_val = cv2.mean(im,mask = mask)
--------------------极点
leftmost = tuple(cnt[cnt[:,:,0].argmin()][0])
rightmost = tuple(cnt[cnt[:,:,0].argmax()][0])
topmost = tuple(cnt[cnt[:,:,1].argmin()][0])
bottommost = tuple(cnt[cnt[:,:,1].argmax()][0])
----------------------------------------轮廓:更多功能
---------------------------凸型缺陷
#OpenCV带有一个现成的函数来找到这个,cv2.convexityDefects()。 基本的函数调用如下所示:
hull = cv2.convexHull(cnt,returnPoints = False)
defects = cv2.convexityDefects(cnt,hull)
注意
记住我们必须在找到凸包时传递returnPoints = False,才能找到凸性缺陷。
它返回一个数组,其中每行包含这些值 - [起始点,终点,最远点,到最远点的近似距离]。
我们可以使用图像进行可视化。 我们画一条加入起点和终点的线,然后在最远点画一个圆。 记住返回的前三个值是cnt的索引。
所以我们必须把这些值从cnt。
import cv2
import numpy as np
img = cv2.imread('star.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(img_gray, 127, 255,0)
contours,hierarchy = cv2.findContours(thresh,2,1)
cnt = contours[0]
hull = cv2.convexHull(cnt,returnPoints = False)
defects = cv2.convexityDefects(cnt,hull)
for i in range(defects.shape[0]):
s,e,f,d = defects[i,0]
start = tuple(cnt[s][0])
end = tuple(cnt[e][0])
far = tuple(cnt[f][0])
cv2.line(img,start,end,[0,255,0],2)
cv2.circle(img,far,5,[0,0,255],-1)
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
--------------------------------------------点多边测试
该功能可以找到图像中某个点与轮廓之间的最短距离。 当点在轮廓外部时,返回的距离为负,当点在内部时为正,如果点在轮廓上,则为零。
例如,我们可以检查点(50,50)如下:
dist = cv2.pointPolygonTest(cnt,(50,50),True)
在函数中,第三个参数是measureDist。 如果为True,则找到已签名的距离。
如果为False,则会发现该点是在内部还是外部还是在轮廓上(分别返回+1,-1,0)。
注意
如果您不想找距离,请确保第三个参数为False,因为这是一个耗时的过程。 所以,使它成为假提供2-3倍加速。
--------------------------------------------匹配形状
OpenCV带有一个函数cv2.matchShapes(),使我们能够比较两个形状或两个轮廓,并返回一个显示相似度的度量。
结果越低,匹配越好。 它是根据hu-moment值计算的。
import cv2
import numpy as np
img1 = cv2.imread('star.jpg',0)
img2 = cv2.imread('star2.jpg',0)
ret, thresh = cv2.threshold(img1, 127, 255,0)
ret, thresh2 = cv2.threshold(img2, 127, 255,0)
contours,hierarchy = cv2.findContours(thresh,2,1)
cnt1 = contours[0]
contours,hierarchy = cv2.findContours(thresh2,2,1)
cnt2 = contours[0]
ret = cv2.matchShapes(cnt1,cnt2,1,0.0)
print ret
==================================================opencv中的直方图=================================================
-------------------------------------直方图1:查找,绘制,分析
使用matplotlib
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('home.jpg',0)
plt.hist(img.ravel(),256,[0,256]); plt.show()
使用opencv
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('home.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()
mask的使用
我们使用cv2.calcHist()来查找完整图像的直方图。 如果要查找图像的某些区域的直方图怎么办?
只需在要查找直方图的区域上创建一个带有白色的蒙版图像,否则为黑色。 然后把它当作面具。
img = cv2.imread('home.jpg',0)
# create a mask
mask = np.zeros(img.shape[:2], np.uint8)
mask[100:300, 100:400] = 255
masked_img = cv2.bitwise_and(img,img,mask = mask)
# Calculate histogram with mask and without mask
# Check third argument for mask
hist_full = cv2.calcHist([img],[0],None,[256],[0,256])
hist_mask = cv2.calcHist([img],[0],mask,[256],[0,256])
plt.subplot(221), plt.imshow(img, 'gray')
plt.subplot(222), plt.imshow(mask,'gray')
plt.subplot(223), plt.imshow(masked_img, 'gray')
plt.subplot(224), plt.plot(hist_full), plt.plot(hist_mask)
plt.xlim([0,256])
plt.show()
------------------------------------------直方图均衡
考虑其像素值仅限于特定值范围的图像。 例如,较亮的图像将所有像素都限制在高值。 但是,一个好的图像将会有来自图像所有区域的像素。
所以你需要将这个直方图拉伸到两端(如下图所示,从维基百科),这就是直方图均衡所做的(简单的话)。 这通常会改善图像的对比度。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('wiki.jpg',0)
hist,bins = np.histogram(img.flatten(),256,[0,256])
cdf = hist.cumsum()
cdf_normalized = cdf * hist.max()/ cdf.max()
plt.plot(cdf_normalized, color = 'b')
plt.hist(img.flatten(),256,[0,256], color = 'r')
plt.xlim([0,256])
plt.legend(('cdf','histogram'), loc = 'upper left')
plt.show()
可以看到直方图位于较亮的区域。 我们需要全谱。 为此,我们需要一个转换函数,将更亮区域中的输入像素映射到全区域的输出像素。
那就是直方图均衡。
现在我们找到最小直方图值(不包括0),并应用维基页面中给出的直方图均衡方程。 但是我在这里使用了来自Numpy的掩码数组概念数组。
对于屏蔽阵列,所有操作都在非屏蔽元素上执行。
cdf_m = np.ma.masked_equal(cdf,0)
cdf_m = (cdf_m - cdf_m.min())*255/(cdf_m.max()-cdf_m.min())
cdf = np.ma.filled(cdf_m,0).astype('uint8')
------------------------------------------------OpenCV中的直方图均衡
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('wiki.jpg',0)
equ = cv2.equalizeHist(img)
res = np.hstack((img,equ)) #stacking images side-by-side
cv2.imwrite('res.png',res)
------------------------------------------------- 对比度有限自适应直方图均衡
import numpy as np
import cv2
img = cv2.imread('tsukuba_l.png',0)
# create a CLAHE object (Arguments are optional).
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
cl1 = clahe.apply(img)
cv2.imwrite('clahe_2.jpg',cl1)
---------------------------------------------------二维直方图
cv2.calcHist()。 对于颜色直方图,我们需要将图像从BGR转换为HSV。 (记住,对于1D直方图,我们从BGR转换为灰度)。
对于2D直方图,其参数将被修改如下:
channel = [0,1],因为我们需要处理H和S平面。
bins= [180,256] 180,H平面为256,S平面为256。
range = [0,180,0,256]色相值介于0和180之间,饱和度介于0和256之间。
import cv2
import numpy as np
img = cv2.imread('home.jpg')
hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
hist = cv2.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
二维直方图用numpy
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('home.jpg')
hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
hist, xbins, ybins = np.histogram2d(h.ravel(),s.ravel(),[180,256],[[0,180],[0,256]])
画二维直方图
Using cv2.imshow()
Using Matplotlib
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('home.jpg')
hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
hist = cv2.calcHist( [hsv], [0, 1], None, [180, 256], [0, 180, 0, 256] )
plt.imshow(hist,interpolation = 'nearest')
plt.show()
------------------------------------------直方图反投影
import cv2
import numpy as np
roi = cv2.imread('rose_red.png')
hsv = cv2.cvtColor(roi,cv2.COLOR_BGR2HSV)
target = cv2.imread('rose.png')
hsvt = cv2.cvtColor(target,cv2.COLOR_BGR2HSV)
# calculating object histogram
roihist = cv2.calcHist([hsv],[0, 1], None, [180, 256], [0, 180, 0, 256] )
# normalize histogram and apply backprojection
cv2.normalize(roihist,roihist,0,255,cv2.NORM_MINMAX)
dst = cv2.calcBackProject([hsvt],[0,1],roihist,[0,180,0,256],1)
# Now convolute with circular disc
disc = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
cv2.filter2D(dst,-1,disc,dst)
# threshold and binary AND
ret,thresh = cv2.threshold(dst,50,255,0)
thresh = cv2.merge((thresh,thresh,thresh))
res = cv2.bitwise_and(target,thresh)
res = np.vstack((target,thresh,res))
cv2.imwrite('res.jpg',res)
================================================opencv 中的图像变换
------------------------------------傅里叶变换
# Numpy有一个FFT包来做到这一点。 np.fft.fft2()为我们提供了一个复杂数组的频率变换。
它的第一个参数是输入图像,这是灰度。 第二个参数是可选的,它决定了输出数组的大小。
如果大于输入图像的大小,则输入图像在计算FFT之前用零填充。 如果小于输入图像,输入图像将被裁剪。
如果没有参数传递,输出数组大小将与输入相同。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('messi5.jpg',0)
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)
magnitude_spectrum = 20*np.log(np.abs(fshift))
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()
通过使用大小为60x60的矩形窗口进行屏蔽来简单地移除低频。 然后使用np.fft.ifftshift()应用反向移位,以便DC分量再次出现在左上角。
然后使用np.ifft2()函数找到逆FFT。 结果又是一个复杂的数字。 你可以把它的绝对价值。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('testset/img4.PNG',0)
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)
rows, cols = img.shape
crow,ccol = rows/2 , cols/2
fshift[crow-30:crow+30, ccol-30:ccol+30] = 0
f_ishift = np.fft.ifftshift(fshift)
img_back = np.fft.ifft2(f_ishift)
img_back = np.abs(img_back)
plt.subplot(131),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(132),plt.imshow(img_back, cmap = 'gray')
plt.title('Image after HPF'), plt.xticks([]), plt.yticks([])
plt.subplot(133),plt.imshow(img_back)
plt.title('Result in JET'), plt.xticks([]), plt.yticks([])
plt.show()
opencv中使用傅里叶变化
import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('messi5.jpg',0)
dft = cv2.dft(np.float32(img),flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)
magnitude_spectrum = 20*np.log(cv2.magnitude(dft_shift[:,:,0],dft_shift[:,:,1]))
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()
去除图像中的高频内容,即我们将LPF应用于图像。
它实际上模糊了图像。 为此,我们首先在低频创建一个具有高值(1)的掩码,即我们通过LF内容,在HF区域通过0。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('testset/img4.PNG',0)
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)
rows, cols = img.shape
crow,ccol = rows/2 , cols/2
# create a mask first, center square is 1, remaining all zeros
mask = np.zeros((rows,cols,2),np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 1
dft = cv2.dft(np.float32(img),flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)
# apply mask and inverse DFT
fshift = dft_shift*mask
f_ishift = np.fft.ifftshift(fshift)
img_back = cv2.idft(f_ishift)
img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1])
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(img_back, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()
===========================================模板匹配
#模板匹配是一种在较大图像中搜索和查找模板图像的位置的方法。 为此,OpenCV带有一个函数cv2.matchTemplate()。
它只需将模板图像滑过输入图像(如2D卷积),并比较模板图像下的输入图像的模板和补丁。 OpenCV中实现了几种比较方法。
(您可以查看文档了解更多详情)。 它返回灰度图像,其中每个像素表示该像素的邻域与模板匹配多少。
如果输入图像的大小(WxH)和模板图像的大小(wxh),则输出图像的大小为(W-w + 1,H-h + 1)。
一旦得到结果,您可以使用cv2.minMaxLoc()函数查找最大/最小值的位置。 将其作为矩形的左上角,并将(w,h)作为矩形的宽度和高度。
那个矩形是你的模板区域
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('messi5.jpg',0)
img2 = img.copy()
template = cv2.imread('template.jpg',0)
w, h = template.shape[::-1]
# All the 6 methods for comparison in a list
methods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR',
'cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED']
for meth in methods:
img = img2.copy()
method = eval(meth)
# Apply template Matching
res = cv2.matchTemplate(img,template,method)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
# If the method is TM_SQDIFF or TM_SQDIFF_NORMED, take minimum
if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
top_left = min_loc
else:
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
cv2.rectangle(img,top_left, bottom_right, 255, 2)
plt.subplot(121),plt.imshow(res,cmap = 'gray')
plt.title('Matching Result'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(img,cmap = 'gray')
plt.title('Detected Point'), plt.xticks([]), plt.yticks([])
plt.suptitle(meth)
plt.show()
-------------------------------------模板匹配多个对象
import cv2
import numpy as np
from matplotlib import pyplot as plt
img_rgb = cv2.imread('mario.png')
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread('mario_coin.png',0)
w, h = template.shape[::-1]
res = cv2.matchTemplate(img_gray,template,cv2.TM_CCOEFF_NORMED)
threshold = 0.8
loc = np.where( res >= threshold)
for pt in zip(*loc[::-1]):
cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0,0,255), 2)
cv2.imwrite('res.png',img_rgb)
=============================================霍夫线变换
import cv2
import numpy as np
img = cv2.imread('dave.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray,50,150,apertureSize = 3)
lines = cv2.HoughLines(edges,1,np.pi/180,200)
for rho,theta in lines[0]:
a = np.cos(theta)
b = np.sin(theta)
x0 = a*rho
y0 = b*rho
x1 = int(x0 + 1000*(-b))
y1 = int(y0 + 1000*(a))
x2 = int(x0 - 1000*(-b))
y2 = int(y0 - 1000*(a))
cv2.line(img,(x1,y1),(x2,y2),(0,0,255),2)
cv2.imwrite('houghlines3.jpg',img)
-----------------------------------概率霍夫线变换
import cv2
import numpy as np
img = cv2.imread('dave.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray,50,150,apertureSize = 3)
minLineLength = 100
maxLineGap = 10
lines = cv2.HoughLinesP(edges,1,np.pi/180,100,minLineLength,maxLineGap)
for x1,y1,x2,y2 in lines[0]:
cv2.line(img,(x1,y1),(x2,y2),(0,255,0),2)
cv2.imwrite('houghlines5.jpg',img)
===========================================霍夫圈变换
import cv2
import numpy as np
img = cv2.imread('opencv_logo.png',0)
img = cv2.medianBlur(img,5)
cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)
circles = cv2.HoughCircles(img,cv2.HOUGH_GRADIENT,1,20,
param1=50,param2=30,minRadius=0,maxRadius=0)
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
# draw the outer circle
cv2.circle(cimg,(i[0],i[1]),i[2],(0,255,0),2)
# draw the center of the circle
cv2.circle(cimg,(i[0],i[1]),2,(0,0,255),3)
cv2.imshow('detected circles',cimg)
cv2.waitKey(0)
cv2.destroyAllWindows()
=============================================图像分割分水岭算法
OpenCV实现了一个基于标记的分水岭算法,您可以在其中指定要合并哪些山谷点,哪些不是。它是一种交互式图像分割。
我们所做的是为我们知道的对象给出不同的标签。标记我们确定是具有一种颜色(或强度)的前景或对象的区域,
标记我们确定为背景的区域或具有另一种颜色的非对象的区域,最后标记我们不确定任何内容的区域,标记为0.这是我们的标记。
然后应用分水岭算法。然后我们的标记将使用我们给出的标签更新,对象的边界将具有-1的值。
import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('testset/img4.PNG')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
# noise removal
kernel = np.ones((3,3),np.uint8)
opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel, iterations = 2)
# sure background area
sure_bg = cv2.dilate(opening,kernel,iterations=3)
# Finding sure foreground area
dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5)
ret, sure_fg = cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0)
# Finding unknown region
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg,sure_fg)
# Marker labelling
ret, markers = cv2.connectedComponents(sure_fg)
# Add one to all labels so that sure background is not 0, but 1
markers = markers+1
# Now, mark the region of unknown with zero
markers[unknown==255] = 0
markers = cv2.watershed(img,markers)
img[markers == -1] = [255,0,0]
==================================================使用GrabCut算法进行交互式前景提取
import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('messi5.jpg')
mask = np.zeros(img.shape[:2],np.uint8)
bgdModel = np.zeros((1,65),np.float64)
fgdModel = np.zeros((1,65),np.float64)
rect = (50,50,450,290)
cv2.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT)
mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')
img = img*mask2[:,:,np.newaxis]
plt.imshow(img),plt.colorbar(),plt.show()
在油漆应用程序中打开输入图像,并向图像添加了另一个图层。 在油漆中使用画笔工具,我在这个新图层上用黑色标记了白色和不需要的背景
(如标志,地面等)的未来前景(头发,鞋子,球等)。 然后用灰色填充剩余的背景。 然后在OpenCV中加载该掩码图像,编辑原始掩码图像,
我们在新添加的掩码图像中得到相应的值。 检查以下代码:
# newmask is the mask image I manually labelled
newmask = cv2.imread('newmask.png',0)
# whereever it is marked white (sure foreground), change mask=1
# whereever it is marked black (sure background), change mask=0
mask[newmask == 0] = 0
mask[newmask == 255] = 1
mask, bgdModel, fgdModel = cv2.grabCut(img,mask,None,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_MASK)
mask = np.where((mask==2)|(mask==0),0,1).astype('uint8')
img = img*mask[:,:,np.newaxis]
plt.imshow(img),plt.colorbar(),plt.show()