opencv图像处理中的一些滤波器+利用滤波器提取条形码(解析二维码)+公交卡倾斜矫正+物体尺寸丈量
一般來說,圖像的能量主要集中在其低頻部分,噪聲所在的頻段主要在高頻段,同時圖像中的細節信息也主要集中在其高頻部分,因此,如何去掉高頻干擾同時又保持細節信息是關鍵。為了去除噪聲,有必要對圖像進行平滑,可以采用低通濾波的方法去除高頻干擾。圖像平滑包括空域法和頻域法兩大類。在空域法中,圖像平滑的常用方法是采用均值濾波或中值濾波。對于均值濾波,它是用一個有奇數點的滑動窗口在圖像上滑動,將窗口中心點對應的圖像像素點的灰度值用窗口內的各個點的灰度值的平均值代替,如果滑動窗口規定了取均值過程中窗口各個像素點所占的權重,也就是各個像素點的系數,這時候就稱為加權均值濾波;對于中值濾波,對應的像素點的灰度值用窗口內的中間值代替。?
一,平滑均值濾波,奇數尺寸,參數和為1,大致的整體描述而模糊一幅圖像,忽略細小的細節,缺點沒有去除噪聲,反而讓圖像模糊,代碼,
""" 平滑濾波 """ def average_filter():img=cv2.imread('./data/opencv_logo.png')kernel=np.ones(shape=(5,5),dtype=np.float32)/25dst=cv2.filter2D(src=img,ddepth=-1,kernel=kernel)plt.subplot(121)plt.imshow(img)plt.title('original')plt.axis('off')plt.subplot(122)plt.imshow(dst)plt.title('Average')plt.axis('off')plt.show()打印結果:
二,平滑高斯濾波,模擬人眼關注中心區域,有效去除高斯噪聲
""" 高斯濾波 """ def image_gauss():img = cv2.imread('./data/img.png')gauss_img = cv2.GaussianBlur(img, (7, 7),0)plt.subplot(121)plt.imshow(img)plt.title('original')plt.axis('off')plt.subplot(122)plt.imshow(gauss_img)plt.title('gauss_img')plt.axis('off')plt.show()打印結果:
三,中值濾波,卷積域內的像素值從小到大排序,取中間值作為卷積輸出,有效去除椒鹽噪聲
""" 中值濾波 """ def image_median():img = cv2.imread('./data/img1.png')median_img = cv2.medianBlur(img,5)plt.subplot(121)plt.imshow(img)plt.title('original')plt.axis('off')plt.subplot(122)plt.imshow(median_img)plt.title('medians_img')plt.axis('off')plt.show()打印結果:
四,Sobel算子
def Sobel(src, ddepth, dx, dy, dst=None, ksize=None, scale=None, delta=None, borderType=None)Sobel算子依然是一種過濾器,只是其是帶有方向的。
前四個是必須的參數:
- 第一個參數是需要處理的圖像;
- 第二個參數是圖像的深度,-1表示采用的是與原圖像相同的深度。目標圖像的深度必須大于等于原圖像的深度;
- dx和dy表示的是求導的階數,0表示這個方向上沒有求導,一般為0、1、2。?
五,傅里葉變換用來分析各種濾波器的頻率特性,圖片中的邊緣點和噪聲可看成是高頻分量,因為變化明顯,沒有很大變化的就看成低頻分量
https://docs.opencv.org/master/de/dbc/tutorial_py_fourier_transform.html
""" 傅利葉變換 """ def FFT():img = cv2.imread('./data/img3.png', 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()在中間部分更亮,表明低頻分量多
用60×60窗口去掉低頻分量
def FFT():img = cv2.imread('./data/img3.png', 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()rows, cols = img.shapecrow, ccol = int(rows / 2), int(cols / 2)fshift[crow - 30:crow + 30, ccol - 30:ccol + 30] = 0f_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()可見只保留了人的邊緣信息,證明了中間亮的那些部分是低頻分量。
六,Laplacian為啥是高通濾波器
def laplace_high_pass():# simple averaging filter without scaling parametermean_filter = np.ones((3,3))# creating a gaussian filterx = cv2.getGaussianKernel(5,10)gaussian = x*x.T# different edge detecting filters# scharr in x-directionscharr = np.array([[-3, 0, 3],[-10,0,10],[-3, 0, 3]])# sobel in x directionsobel_x= np.array([[-1, 0, 1],[-2, 0, 2],[-1, 0, 1]])# sobel in y directionsobel_y= np.array([[-1,-2,-1],[0, 0, 0],[1, 2, 1]])# laplacianlaplacian=np.array([[0, 1, 0],[1,-4, 1],[0, 1, 0]])filters = [mean_filter, gaussian, laplacian, sobel_x, sobel_y, scharr]filter_name = ['mean_filter', 'gaussian','laplacian', 'sobel_x', \'sobel_y', 'scharr_x']fft_filters = [np.fft.fft2(x) for x in filters]fft_shift = [np.fft.fftshift(y) for y in fft_filters]mag_spectrum = [np.log(np.abs(z)+1) for z in fft_shift]for i in range(6):plt.subplot(2,3,i+1),plt.imshow(mag_spectrum[i],cmap = 'gray')plt.title(filter_name[i]), plt.xticks([]), plt.yticks([])plt.show()打印結果:
中間有白色的部分代表是低通濾波器,中間有黑色的部分代表是高通濾波器。
七,圖像銳化
圖像的邊緣信息在圖像風險和人的視覺中都是非常重要的,物體的邊緣是以圖像局部特性不連續的形式出現的。前面介紹的圖像濾波對于消除噪聲是有益的,但往往使圖像中的邊界、輪廓變的模糊,為了減少這類不利效果的影響,就需要利用圖像銳化技術,使圖像的邊緣變得更加鮮明。圖像銳化處理的目的就是為了使圖像的邊緣、輪廓線以及圖像的細節變得清晰,經過平滑處理后的圖像變得模糊的根本原因是因為圖像的像素受到了平均或積分,因此對其進行逆運算(如微分運算)就可以使圖像變得清晰。從頻率域來考慮,圖像模糊的實質是因為其高頻分量被衰減,因此可以用高通濾波器使圖像清晰。
八.例子 提取條形碼
1.1 利用梯度操作是如何檢測出圖片的條形碼;
1.2 利用均值濾波作用于梯度圖片,平滑圖片中的高頻噪聲;
1.3 二值化;
1.4 利用函數cv2.getStructuringElement構造一個矩形核做閉運算,這個核的寬度大于高度,因此允許我們縮小條形碼垂直條帶之間的間隙;
1.5 腐蝕,膨脹去掉大部分獨立斑點;
1.6 找出最大輪廓,提取。
import cv2 import matplotlib.pyplot as plt import numpy as np import imutils path='./barcode.png' image = cv2.imread(path) image_h, image_w,_=image.shape print('======opencv read data type========') print(image.dtype) gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# # 計算圖片x和y方向的Scharr梯度大小 ddepth = cv2.CV_32F if imutils.is_cv2() else cv2.CV_32F gradX = cv2.Sobel(gray, ddepth=ddepth , dx=1, dy=0, ksize=-1) print('gradX.dtype:',gradX.dtype)# # #debug # gradX = cv2.convertScaleAbs(gradX) # print(gradX.dtype) # cv2.imshow('gradX',gradX) # cv2.waitKey(0)gradY = cv2.Sobel(gray, ddepth=ddepth , dx=0, dy=1, ksize=-1) # # #debug # gradY = cv2.convertScaleAbs(gradY) # print(gradY.dtype) # cv2.imshow('gradY',gradY) # cv2.waitKey(0)# 用x方向的梯度減去y方向的梯度 gradient = cv2.subtract(gradX,gradY) # cv2.imshow('gradient1',gradient) # cv2.waitKey(0)#轉回uint8 gradient = cv2.convertScaleAbs(gradient) # print(gradient.shape) # print(gradient.dtype) # cv2.imshow('gradient2',gradient) # cv2.waitKey(0)# blur and threshold the image blurred = cv2.blur(gradient, (9, 9)) thresh= cv2.threshold(blurred, 225, 255, cv2.THRESH_BINARY)[1]# cv2.imshow('thresh:',thresh) # cv2.waitKey(0) # construct a closing kernel and apply it to the thresholded image kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (21, 7)) closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel) # cv2.imshow('closed:',closed) # cv2.waitKey(0) # perform a series of erosions and dilations closed = cv2.erode(closed, None, iterations = 4) closed = cv2.dilate(closed, None, iterations = 4) # cv2.imshow('close:',closed) # cv2.waitKey(0)# find the contours in the thresholded image, then sort the contours # by their area, keeping only the largest one cnts = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = imutils.grab_contours(cnts) # cnts = cnts[0] c = sorted(cnts, key=cv2.contourArea, reverse=True) c = np.squeeze(c[0]) # plt.plot(c[:, 0], c[:, 1]) # plt.show() mask = np.zeros((image_h, image_w, 3)) dummy_mask = cv2.drawContours(mask, [c], 0, (255, 255, 255), thickness=cv2.FILLED) cv2.imshow('dummy_mask',dummy_mask) cv2.waitKey(0)image_bar=(image*(np.array(dummy_mask/255).astype(np.uint8))) cv2.imshow('image_bar',image_bar) cv2.waitKey(0)? ?? ?
用下面這個是提取出輪廓的外接多邊形然后框出來
rect=cv2.minAreaRect(c)#get center xy and w h box = cv2.boxPoints(rect) # cv2.boxPoints(rect) for OpenCV 3.x 獲取最小外接矩形的4個頂點坐標 box = np.int0(box) print(box) cv2.drawContours(image, [box], 0, (0, 255, 0), 3)cv2.imshow('image',image) cv2.waitKey(0)2.1?解析二維碼
import pyzbar.pyzbar as pyzbarimg = cv2.imread('./2.png')gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) gray_h, gray_w = gray.shape barcodes = pyzbar.decode(gray) print('==barcodes:', barcodes)def parse_results(barcode):# for barcode in barcodes:# 提取二維碼的位置(x, y, w, h) = barcode.rect# 字符串轉換barcodeData = barcode.data.decode("utf-8")# barcodeType = barcode.typereturn x, y, x + w, y + h, barcodeDataif len(barcodes):print('==barcodes[0]:', barcodes[0])x1, y1, x2, y2, barcodeData = parse_results(barcodes[0])print('==barcodeData:', barcodeData)?
?
九.傾斜矯正
#from imutils.perspective import four_point_transform #import imutils import cv2 import numpy as np from matplotlib import pyplot as plt import mathdef Get_Outline(input_dir):image = cv2.imread(input_dir)gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)blurred = cv2.GaussianBlur(gray, (5, 5), 0)edged = cv2.Canny(blurred, 75, 200)return image, gray, edgeddef Get_cnt(edged):cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)cnts = cnts[0] # if imutils.is_cv2() else cnts[1]docCnt = Noneif len(cnts) > 0:cnts = sorted(cnts, key=cv2.contourArea, reverse=True)for c in cnts:peri = cv2.arcLength(c, True) # 輪廓按大小降序排序approx = cv2.approxPolyDP(c, 0.02 * peri, True) # 獲取近似的輪廓if len(approx) == 4: # 近似輪廓有四個頂點docCnt = approxbreakreturn docCntdef calculate_distance(point1, point2):d_x = point1[0] - point2[0]d_y = point1[1] - point2[1]distance = math.sqrt(d_x ** 2 + d_y ** 2)return distanceif __name__ == "__main__":input_dir = "gongjiaoka.png"image, gray, edged = Get_Outline(input_dir)docCnt = Get_cnt(edged)# print(docCnt)print(docCnt.reshape(4, 2))# result_img = four_point_transform(image, docCnt.reshape(4,2)) # 對原始圖像進行四點透視變換# 改變變換的模式 公交卡的比例是16:9pts1 = np.float32(docCnt.reshape(4, 2))# 加入一個判斷,對不同寬高采用不同的系數p = docCnt.reshape(4, 2)# plt.plot(p[:,0],p[:,1])# plt.show()# 確定長短邊if calculate_distance(p[0], p[1]) < calculate_distance(p[0], p[3]):pts2 = np.float32([[0, 0], [0, 180], [320, 180], [320, 0]])M = cv2.getPerspectiveTransform(pts1, pts2)#求仿射變換矩陣edged_rotate = cv2.warpPerspective(edged, M, (320, 180))image_rotate = cv2.warpPerspective(image, M, (320, 180))else:pts2 = np.float32([[0, 0], [0, 320], [180, 320], [180, 0]])#求仿射變換矩陣 M = cv2.getPerspectiveTransform(pts1, pts2)edged_rotate = cv2.warpPerspective(edged, M, (180, 320))image_rotate = cv2.warpPerspective(image, M, (180, 320))cv2.imwrite('image_rotate.png',image_rotate)# print(result_img.shape)# -------畫點----------for point in docCnt.reshape(4, 2):cv2.circle(image, tuple(point), 3, (0, 0, 255), 2)# # --------------cv2.imshow("original", image)# cv2.imshow("gray", gray)cv2.imshow("edged", edged)cv2.imshow("edged_rotate", edged_rotate)cv2.imshow("result_img", image_rotate)cv2.waitKey(0)cv2.destroyAllWindows()十.求物體尺寸
from scipy.spatial import distance as dist from imutils import perspective from imutils import contours import numpy as np import argparse import imutils import cv2def midpoint(ptA, ptB):return ((ptA[0] + ptB[0]) * 0.5, (ptA[1] + ptB[1]) * 0.5)path='./img/example_02.png' #硬幣長度0.955inch WIDTH=0.955 # load the image, convert it to grayscale, and blur it slightly image = cv2.imread(path) gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) gray = cv2.GaussianBlur(gray, (7, 7), 0)# cv2.imwrite('gray.jpg',gray)edged = cv2.Canny(gray, 50, 100) edged = cv2.dilate(edged, None, iterations=1) edged = cv2.erode(edged, None, iterations=1)# find contours in the edge map cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = cnts[0] if imutils.is_cv2() else cnts[1] cnts = sorted(cnts, key=cv2.contourArea, reverse=True) # print(len(cnts)) # print(cnts[0].shape) pixelsPerMetric = None orig = image.copy()for c in cnts:if cv2.contourArea(c) < 100:continuebox = cv2.minAreaRect(c)box = cv2.cv.BoxPoints(box) if imutils.is_cv2() else cv2.boxPoints(box)box = np.array(box, dtype="int")print('box:',box)box = perspective.order_points(box)cv2.drawContours(orig, [box.astype("int")], -1, (0, 255, 0), 2)for (x, y) in box:cv2.circle(orig, (int(x), int(y)), 5, (0, 0, 255), -1)(tl, tr, br, bl) = box(tltrX, tltrY) = midpoint(tl, tr)(blbrX, blbrY) = midpoint(bl, br)(tlblX, tlblY) = midpoint(tl, bl)(trbrX, trbrY) = midpoint(tr, br)# draw the midpoints on the imagecv2.circle(orig, (int(tltrX), int(tltrY)), 5, (255, 0, 0), -1)cv2.circle(orig, (int(blbrX), int(blbrY)), 5, (255, 0, 0), -1)cv2.circle(orig, (int(tlblX), int(tlblY)), 5, (255, 0, 0), -1)cv2.circle(orig, (int(trbrX), int(trbrY)), 5, (255, 0, 0), -1)# draw lines between the midpointscv2.line(orig, (int(tltrX), int(tltrY)), (int(blbrX), int(blbrY)),(255, 0, 255), 2)cv2.line(orig, (int(tlblX), int(tlblY)), (int(trbrX), int(trbrY)),(255, 0, 255), 2)# compute the Euclidean distance between the midpointsdA = dist.euclidean((tltrX, tltrY), (blbrX, blbrY))dB = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))# if the pixels per metric has not been initialized, then# compute it as the ratio of pixels to supplied metric# (in this case, inches)if pixelsPerMetric is None:pixelsPerMetric = dB / WIDTH# compute the size of the objectdimA = dA / pixelsPerMetricdimB = dB / pixelsPerMetric# draw the object sizes on the imagecv2.putText(orig, "{:.1f}in".format(dimA),(int(tltrX - 15), int(tltrY - 10)), cv2.FONT_HERSHEY_SIMPLEX,0.65, (255, 255, 255), 2)cv2.putText(orig, "{:.1f}in".format(dimB),(int(trbrX + 10), int(trbrY)), cv2.FONT_HERSHEY_SIMPLEX,0.65, (255, 255, 255), 2) cv2.imwrite('orig.jpg', orig) 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的opencv图像处理中的一些滤波器+利用滤波器提取条形码(解析二维码)+公交卡倾斜矫正+物体尺寸丈量的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 利用tensorflow构建AlexNe
- 下一篇: 23篇大数据系列(二)scala基础知识