OpenCV读书笔记

Posted 河南骏

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenCV读书笔记相关的知识,希望对你有一定的参考价值。

==============================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)
---------------------------------------------凸包
看起来类似于轮廓近似,但它不是(两者可能在某些情况下提供相同的结果)。

以上是关于OpenCV读书笔记的主要内容,如果未能解决你的问题,请参考以下文章

text “OpenCV3编程入门”读书笔记

OpenCV读书笔记

OpenCV3编程入门--读书笔记

一文入门推荐系统——推荐系统实践读书笔记

python下使用OpenCV实现计算机视觉读书笔记2图像与字节的变换

Python深度学习:OpenCV图像处理实战 HSV处理,图像旋转平移(读书笔记)