Canny边缘检测

(一)、只进行canny边缘检测

效果图:

(原图)


(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边缘检测。


效果图:

(步骤(1)——(4)后效果图)

(步骤(5)效果图)


代码(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()

备注:以上代码可实现调取摄像头,截图、录像等功能


猜你喜欢

转载自blog.csdn.net/qq_33215407/article/details/80251299