(一)、只进行canny边缘检测
效果图:
代码(Python3.6 + OpenCV3):
import cv2
import numpy as np
img = cv2.imread("F:\python\data\photos\screenshot1.png",0)
cv2.imwrite("creenshot1canny.jpg",cv2.Canny(img,200,300))
cv2.imshow("mycanny",cv2.imread("creenshot1canny.jpg"))
cv2.waitKey()
cv2.destroyAllWindows()
(二)滤波后使用canny边缘检测
(1)先使用medianBlur()作为模糊函数,去除噪声;
(2)将图像从BGR转成灰度图;
(3)使用Laplacian()作为边缘检测函数,产生明显的边缘线条;
(4)转换为黑色边缘和白色背景,归一化(像素0到1之间),并乘以源图像;
(5)canny边缘检测。
效果图:
代码(Python3.6 + OpenCV3):
cameo.py
import cv2
import Opencv_test.filters
from Opencv_test.managers import WindowManager, CaptureManager
class Cameo(object):
def __init__(self):
self._windowManager = WindowManager('Camo', self.onKeypress)
self._captureManager = CaptureManager(cv2.VideoCapture(0), self._windowManager, True)
self._curveFilter = Opencv_test.filters.BGRPortraCurveFilter()#新增
def run(self):
"""运行main"""
self._windowManager.createWindow()
while self._windowManager.isWindowCreated:
self._captureManager.enterFrame()
frame = self._captureManager.frame
Opencv_test.filters.strokeEdges(frame,frame)#新增
self._curveFilter.apply(frame,frame)#新增
self._captureManager.exitFrame()
self._windowManager.processEvents()
def onKeypress(self, keycode):
"""设置按键
空格 -> 截图
tab -> 开始/暂停视频截取
esc -> 退出窗口
"""
if keycode == 32: # 空格
self._captureManager.writeImage('F:\python\data\photos\screenshot.png')
elif keycode == 9: # tab
if not self._captureManager.isWritingVideo:
self._captureManager.startWritingVideo('F:\python\data\photos\screencast.avi')
else:
self._captureManager.stopWritingVideo()
elif keycode == 27: # esc
self._windowManager.destroyWindow()
if __name__ == "__main__":
Cameo().run()
managers.py
import cv2
import numpy
import time
class CaptureManager(object):
def __init__(self, capture, previewWindowManager=None,shouldMirrorPreview=False):
self.previewWindowManager = previewWindowManager
self.shouldMirrorPreview = shouldMirrorPreview
self._capture = capture
self._channel = 0
self._enteredFrame = False
self._frame = None
self._imageFilename = None
self._videoFilename = None
self._videoEncoding = None
self._videoWriter = None
self._startTime = None
self._framesElapsed = numpy.long(0)
self._fpsEstimate = None
@property
def channel(self):
return self._channel
@channel.setter
def channel(self, value):
if self._channel != value:
self._channel = value
self._frame = None
@property
def frame(self):
if self._enteredFrame and self._frame is None:
_, self._frame = self._capture.retrieve()
return self._frame
@property
def isWritingImage(self):
return self._imageFilename is not None
@property
def isWritingVideo(self):
return self._videoFilename is not None
def enterFrame(self):
""" 获取下一帧 """
#但首先检查以前的帧是否退出
assert not self._enteredFrame, 'previous enterFrame() had no matching exitFrame()'
if self._capture is not None:
self._enteredFrame = self._capture.grab()
def exitFrame(self):
""" 设置出窗口,写入文件,释放框架"""
# 检查是否有抓取的框架是可检索的
if self.frame is None:
self._enteredFrame = False
return
# 更新FPS估值和相关变量
if self._framesElapsed == 0:
self._startTime = time.time()
else:
timeElapsed = time.time() - self._startTime
self._fpsEstimate = self._framesElapsed / timeElapsed
self._framesElapsed += 1
# 设置窗口。
if self.previewWindowManager is not None:
if self.shouldMirrorPreview:
mirroredFrame = numpy.fliplr(self._frame).copy()
self.previewWindowManager.show(mirroredFrame)
else:
self.previewWindowManager.show(self._frame)
# 写入图像文件
if self.isWritingImage:
cv2.imwrite(self._imageFilename, self._frame)
self._imageFilename = None
# 写入视频文件
self._writeVideoFrame()
# 释放框架
self._frame = None
self._enteredFrame = False
def writeImage(self, filename):
"""将下一个退出的帧写入图像文件"""
self._imageFilename = filename
def startWritingVideo(self, filename,
encoding=cv2.VideoWriter_fourcc('I', '4', '2', '0')):
self._videoFilename = filename
self._videoEncoding = encoding
def stopWritingVideo(self):
"""停止写入视频文件 """
self._videoFilename = None
self._videoEncoding = None
self._videoWriter = None
def _writeVideoFrame(self):
if not self.isWritingVideo:
return
if self._videoWriter is None:
fps = self._capture.get(cv2.CAP_PROP_FPS)
if fps == 0.0:
# 捕获的FPS是未知的,所以使用估计值
if self._framesElapsed < 20:
return
else:
fps = self._fpsEstimate
size = (int(self._capture.get(cv2.CAP_PROP_FRAME_WIDTH)),
int(self._capture.get(cv2.CAP_PROP_FRAME_HEIGHT)))
self._videoWriter = cv2.VideoWriter(
self._videoFilename, self._videoEncoding, fps, size)
self._videoWriter.write(self._frame)
class WindowManager(object):
def __init__(self, windowName, keypresscallback=None):
self.keypressCallback = keypresscallback
self._windowName = windowName
self._isWindowCreated = False
@property
def isWindowCreated(self):
return self._isWindowCreated
def createWindow(self):
cv2.namedWindow(self._windowName)
self._isWindowCreated = True
def show(self, frame):
cv2.imshow(self._windowName, frame)
def destroyWindow(self):
cv2.destroyWindow(self._windowName)
self._isWindowCreated = False
def processEvents(self):
keycode = cv2.waitKey(1)
if self.keypressCallback is not None and keycode != -1:
keycode &= 0xFF
self.keypressCallback(keycode)
filters.py
import cv2
import numpy
import Opencv_test.utils
def strokeEdges(src,dst,blurKsize = 7,edgeKsize = 5):
if blurKsize >= 3:
blurredSrc = cv2.medianBlur(src,blurKsize)
graySrc = cv2.cvtColor(blurredSrc,cv2.COLOR_BGR2GRAY)
else:
graySrc = cv2.cvtColor(src, cv2.COLOR_BAYER_BG2BGR)
cv2.Laplacian(graySrc, cv2.CV_8U, graySrc, ksize=edgeKsize)
normalizedInverseAlpha = (1.0 / 255) * (255 - graySrc)
channels = cv2.split(src)
for channel in channels:
channel[:] = channel * normalizedInverseAlpha
cv2.merge(channels,dst)
class BGRFuncFilter(object):
def __init__(self, vFunc = None, bFunc = None, gFunc = None, rFunc = None,dtype = numpy.uint8) :
length = numpy.iinfo(dtype).max + 1
self._bLookupArray = Opencv_test.utils.createLookupArray(Opencv_test.utils.createCompositeFunc(bFunc, vFunc), length)
self._gLookupArray = Opencv_test.utils.createLookupArray(Opencv_test.utils.createCompositeFunc(gFunc, vFunc), length)
self._rLookupArray = Opencv_test.utils.createLookupArray(Opencv_test.utils.createCompositeFunc(rFunc, vFunc), length)
def apply(self, src, dst) :
"""Apply the filter with a BGR source/destination."""
b, g, r = cv2.split(src)
Opencv_test.utils.applyLookupArray(self._bLookupArray, b, b)
Opencv_test.utils.applyLookupArray(self._gLookupArray, g, g)
Opencv_test.utils.applyLookupArray(self._rLookupArray, r, r)
cv2.merge([ b, g, r ], dst)
class BGRCurveFilter(BGRFuncFilter):
def __init__(self, vPoints = None, bPoints = None,gPoints = None, rPoints = None, dtype = numpy.uint8):
BGRFuncFilter.__init__(self, Opencv_test.utils.createCurveFunc(vPoints), Opencv_test.utils.createCurveFunc(bPoints),
Opencv_test.utils.createCurveFunc(gPoints), Opencv_test.utils.createCurveFunc(rPoints), dtype)
class BGRPortraCurveFilter(BGRCurveFilter):
def __init__(self, dtype = numpy.uint8):
BGRCurveFilter.__init__(
self,
vPoints = [ (0, 0), (23, 20), (157, 173), (255, 255) ],
bPoints = [ (0, 0), (41, 46), (231, 228), (255, 255) ],
gPoints = [ (0, 0), (52, 47), (189, 196), (255, 255) ],
rPoints = [ (0, 0), (69, 69), (213, 218), (255, 255) ],
dtype = dtype)
utils.py
import cv2,numpy,scipy.interpolate
def createCurveFunc(points):
"""Return a function derived from control points."""
if points is None:
return None
num_points = len(points)
if num_points < 2:
return None
xs, ys = zip(*points)
if num_points < 4:
kind = 'linear'
# 'quadratic' is not implemented.
else:
kind = 'cubic'
return scipy.interpolate.interp1d(xs, ys, kind,bounds_error = False)
def createLookupArray(func, length = 256):
"""Return a lookup for whole-number inputs to a function. The lookup values are clamped to [0, length - 1]."""
if func is None:
return None
lookup_array = numpy.empty(length)
i = 0
while i < length:
func_i = func(i)
lookup_array[i] = min(max(0, func_i), length - 1)
i += 1
return lookup_array
def applyLookupArray(lookup_array, src, dst):
"""Map a source to a destination using a lookup."""
if lookup_array is None:
return
dst[:] = lookup_array[src]
def createCompositeFunc(func0, func1):
"""Return a composite of two functions."""
if func0 is None:
return func1
if func1 is None:
return func0
return lambda x: func0(func1(x))
def createFlatView(array):
"""Return a 1D view of an array of any dimensionality."""
flat_view = array.view()
flat_view.shape = array.size
return flat_view
canny.py
import cv2
import numpy as np
img = cv2.imread("F:\python\data\photos\screenshot1.png",0)
cv2.imwrite("creenshot1canny.jpg",cv2.Canny(img,200,300))
cv2.imshow("mycanny",cv2.imread("creenshot1canny.jpg"))
cv2.waitKey()
cv2.destroyAllWindows()
备注:以上代码可实现调取摄像头,截图、录像等功能