国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Python-OpenCV中的圖像處理-圖像輪廓

這篇具有很好參考價(jià)值的文章主要介紹了Python-OpenCV中的圖像處理-圖像輪廓。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

輪廓

什么是輪廓

輪廓可以簡(jiǎn)單認(rèn)為成將連續(xù)的點(diǎn)(連著邊界)連在一起的曲線,具有相同的顏色或者灰度。輪廓在形狀分析和物體的檢測(cè)和識(shí)別中很有用。

  • 為了更加準(zhǔn)確,要使用二值化圖像。在尋找輪廓之前,要進(jìn)行閾值化處理或者 Canny 邊界檢測(cè)。
  • 查找輪廓的函數(shù)會(huì)修改原始圖像。如果你在找到輪廓之后還想使用原始圖像的話,你應(yīng)該將原始圖像存儲(chǔ)到其他變量中。
  • 在 OpenCV 中,查找輪廓就像在黑色背景中超白色物體。你應(yīng)該記住,要找的物體應(yīng)該是白色而背景應(yīng)該是黑色。

查找輪廓

函數(shù) cv2.findContours() 有三個(gè)參數(shù),第一個(gè)是輸入圖像,第二個(gè)是輪廓檢索模式,第三個(gè)是輪廓近似方法。返回值有三個(gè),第一個(gè)是圖像,第二個(gè)是輪廓,第三個(gè)是(輪廓的)層析結(jié)構(gòu)。輪廓(第二個(gè)返回值)是一個(gè) Python列表,其中存儲(chǔ)這圖像中的所有輪廓。每一個(gè)輪廓都是一個(gè) Numpy 數(shù)組,包含對(duì)象邊界點(diǎn)( x, y)的坐標(biāo)。

ret, thresh = cv2.threshold(imgray, 127, 255, 0)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

cv2.CHAIN_APPROX_NONE:儲(chǔ)存所有的邊界點(diǎn)(點(diǎn)數(shù)很多)
cv2.CHAIN_APPROX_SIMPLE:儲(chǔ)存所有的近似直線點(diǎn)(點(diǎn)數(shù)很少)

繪制輪廓

函數(shù) cv2.drawContours() 可以被用來(lái)繪制輪廓。它可以根據(jù)你提供的邊界點(diǎn)繪制任何形狀。它的第一個(gè)參數(shù)是原始圖像,第二個(gè)參數(shù)是輪廓,一個(gè) Python 列表。第三個(gè)參數(shù)是輪廓的索引(在繪制獨(dú)立輪廓是很有用,當(dāng)設(shè)置為 -1 時(shí)繪制所有輪廓)。接下來(lái)的參數(shù)是輪廓的顏色和厚度等。

  • 繪制所有輪廓 image = cv2.drawContours(img, contours, -1, (0, 255, 0), 3)
  • 繪制指定輪廓 image = cv2.drawContours(img, contours, 0, (0, 255, 0), 3)
import numpy as np
import cv2

# 輪廓:連著邊界連續(xù)的點(diǎn)連在一起的曲線,具有相同的顏色或者灰度。
# 輪廓在形狀分析和物體的檢測(cè)和識(shí)別中很有用。

# 1.為了準(zhǔn)確,要使用二值化圖像。需要進(jìn)行閥值化處理或Canny邊界檢測(cè)。
# 2.查找輪廓的函數(shù)會(huì)修改元素圖像。
# 3.在OpenCV中,查找輪廓就像在黑色背景中找白色物體。

# cv2.findContours() # 查找輪廓
# cv2.drawContours() # 繪制輪廓

img = cv2.imread('./resource/image/opencv-logo2.png')
imgcp = cv2.imread('./resource/image/opencv-logo2.png')
imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)



ret, thresh = cv2.threshold(imgray, 127, 255, 0)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# contours 輪廓
# hierarchy 層次

# image = cv2.drawContours(img, contours, -1, (0, 255, 0), 3) # 繪制所有輪廓
image = cv2.drawContours(img, contours, 3, (0, 255, 0), 3) # 繪制第4個(gè)輪廓
print(cv2.getVersionString())
print(type(contours))
print(len(contours))
cv2.imshow('img', imgcp)
cv2.imshow('image', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

Python-OpenCV中的圖像處理-圖像輪廓,OpenCV Python,python,opencv,圖像處理

輪廓特征

  • 查找輪廓的不同特征:矩、面積、周長(zhǎng)(也叫弧長(zhǎng))、重心、邊界框等

圖像的矩

  • 在圖像處理、計(jì)算機(jī)視覺(jué)和相關(guān)領(lǐng)域,圖像矩是圖像像素強(qiáng)度的某個(gè)特定的加權(quán)平均值(矩),或者是這種矩的函數(shù),通常被選擇為具有某種吸引人的特性或解釋。圖像矩在分割后對(duì)描述物體很有用。通過(guò)圖像矩找到的圖像的簡(jiǎn)單屬性包括面積(或總強(qiáng)度)、其中心點(diǎn)和關(guān)于其方向的信息。
  • 圖像的矩可以幫助我們計(jì)算圖像的質(zhì)心,面積等。
  • 函數(shù)cv2.moments()計(jì)算得到矩,返回一個(gè)字典。
    根據(jù)矩值可以計(jì)算對(duì)象的重心:
    C x = M 10 M 00 , C y = M 01 M 00 C_x=\frac{M_{10}}{M_{00}},C_y=\frac{M_{01}}{M_{00}} Cx?=M00?M10??,Cy?=M00?M01??
import numpy as np
import cv2
from matplotlib import pyplot as plt

# 矩:圖像的矩可以幫助我們計(jì)算圖像的質(zhì)心,面積等
# cv2.moments() 計(jì)算得到矩,以一個(gè)字典形式返回

# 讀取圖像
img = cv2.imread('./resource/opencv/image/box2.png', cv2.IMREAD_COLOR)
img1 = img.copy()
gray = cv2.imread('./resource/opencv/image/box2.png', cv2.IMREAD_GRAYSCALE)

# 閥值處理
(ret, thresh) = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

# 查找所有輪廓
(contours, hierarchy) = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
print('找到輪廓數(shù):',len(contours))

# 計(jì)算輪廓索引為0的圖像矩
cnt = contours[0]
M = cv2.moments(cnt)
print('moments()計(jì)數(shù)結(jié)果M:',M)

# 計(jì)算重心(質(zhì)點(diǎn))
#根據(jù)這些矩值計(jì)算出對(duì)象的重心:
# Cx = M10/M00
# Cy = M01/M00
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
print(cx,cy)

# 繪制輪廓
cv2.drawContours(img1, contours, 0, (0, 255, 0), 2)

# 繪制質(zhì)點(diǎn)
cv2.circle(img1, (cx, cy), 5, (255, 0, 0), -1)

plt.subplot(121), plt.imshow(img)
plt.subplot(122), plt.imshow(img1)
plt.show()

程序運(yùn)行結(jié)果:
找到輪廓數(shù): 1
moments()計(jì)數(shù)結(jié)果M: {‘m00’: 10032.0, ‘m10’: 1294128.0, ‘m01’: 1284096.0, ‘m20’: 177807168.0, ‘m11’: 165648384.0, ‘m02’: 170838272.0, ‘m30’: 25740205920.0, ‘m21’: 22759317504.0, ‘m12’: 22038137088.0, ‘m03’: 23524638720.0, ‘mu20’: 10864656.0, ‘mu11’: 0.0, ‘mu02’: 6473984.0, ‘mu30’: 0.0, ‘mu21’: 0.0, ‘mu12’: 0.0, ‘mu03’: 0.0, ‘nu20’: 0.10795454545454546, ‘nu11’: 0.0, ‘nu02’: 0.06432748538011696, ‘nu30’: 0.0, ‘nu21’: 0.0, ‘nu12’: 0.0, ‘nu03’: 0.0}
質(zhì)點(diǎn): 129 128

下圖紅色圓點(diǎn)是質(zhì)點(diǎn),綠色框是輪廓:
Python-OpenCV中的圖像處理-圖像輪廓,OpenCV Python,python,opencv,圖像處理

輪廓面積

  • 輪廓的面積可以使用函數(shù) cv2.contourArea() 計(jì)算得到,也可以使用矩
    ( 0 階矩), M[‘m00’]。
  • area = cv2.contourArea(cnt)
import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread('./resource/opencv/image/box2.png', cv2.IMREAD_COLOR)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

(ret, thresh) = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
(contours, hierarchy) = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

cnt = contours[0]
M = cv2.moments(cnt)
area = cv2.contourArea(cnt)
print(cnt)
print(area)
print(M['m00'])

[[[ 72 84]]
[[ 72 172]]
[[186 172]]
[[186 84]]]
10032.0
10032.0

輪廓周長(zhǎng)(弧長(zhǎng))

  • 也被稱為弧長(zhǎng)??梢允褂煤瘮?shù) cv2.arcLength() 計(jì)算得到。這個(gè)函數(shù)的第二參數(shù)可以用來(lái)指定對(duì)象的形狀是閉合的( True),還是打開(kāi)的(一條曲線)。
  • perimeter = cv2.arcLength(cnt,True)
import numpy as np
import cv2

img = cv2.imread('./resource/opencv/image/box2.png', cv2.IMREAD_COLOR)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

(ret, thresh) = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
(contours, hierarchy) = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# 第一個(gè)參數(shù)輪廓,第二次參數(shù)形狀閉合的(True),還是打開(kāi)的一條曲線
perimeter = cv2.arcLength(contours[0], True)
print(perimeter) #404.0

輪廓近似

  • 將輪廓形狀近似到另外一種由更少點(diǎn)組成的輪廓形狀,新輪廓的點(diǎn)的數(shù)目由我們?cè)O(shè)定的準(zhǔn)確度來(lái)決定。使用的Douglas-Peucker算法,維基百科獲得更多此算法的細(xì)節(jié)。
  • 假設(shè)要在一幅圖像中查找一個(gè)矩形,但是由于圖像的種種原因,我們不能得到一個(gè)完美的矩形,而是一個(gè)“壞形狀”?,F(xiàn)在你就可以使用這個(gè)函數(shù)來(lái)近似這個(gè)形狀()了。
  • epsilon = 0.1*cv2.arcLength(cnt,True)
    approx = cv2.approxPolyDP(cnt,epsilon,True)
import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread('./resource/opencv/image/approx2.jpg', cv2.IMREAD_COLOR)
img_draw1 = img.copy()
img_draw2 = img.copy()

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
(ret, thresh) = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
(contours, hierarchy) = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# epsilon=10%
epsilon01 = 0.1 * cv2.arcLength(contours[0], True)
# epsilon=1%
epsilon001  = 0.01 * cv2.arcLength(contours[0], True)
approx_01 = cv2.approxPolyDP(contours[0], epsilon01, True)
approx_001 = cv2.approxPolyDP(contours[0], epsilon001, True)

cv2.drawContours(img_draw1, approx_01, -1, (0, 0, 255), 5)
cv2.drawContours(img_draw2, approx_001, -1, (0, 0, 255), 5)

plt.subplot(131), plt.imshow(img), plt.title('original')
plt.subplot(132), plt.imshow(img_draw1), plt.title('epsilon=10%')
plt.subplot(133), plt.imshow(img_draw2), plt.title('epsilon=1%')
plt.show()

Python-OpenCV中的圖像處理-圖像輪廓,OpenCV Python,python,opencv,圖像處理

凸包

  • 凸包與輪廓近似相似,但不同,雖然有些情況下它們給出的結(jié)果是一樣的。
  • 函數(shù) cv2.convexHull() 可以用來(lái)檢測(cè)一個(gè)曲線是否具有凸性缺陷,并能糾正缺陷。
    hull = cv2.convexHull(points[, hull[, clockwise[, returnPoints]])
    參數(shù):
    points:傳入的輪廓
    hull:輸出,通常不需要
    clockwise:方向標(biāo)志,True:輸出的凸包是順時(shí)針?lè)较?,F(xiàn)alse:逆時(shí)針?lè)较颉?br> returnPoints:默認(rèn)值為T(mén)rue:返回凸包上點(diǎn)的坐標(biāo)。False:返回與凸包點(diǎn)對(duì)應(yīng)的輪廓上的點(diǎn)。
  • 獲取凸包:hull = cv2.convexHull(cnt)
  • 一般來(lái)說(shuō),凸性曲線總是凸出來(lái)的,至少是平的。如果有地方凹進(jìn)去了就被叫做凸性缺陷。例如下圖中的手。紅色曲線顯示了手的凸包,凸性缺陷被雙箭頭標(biāo)出來(lái)了。
    Python-OpenCV中的圖像處理-圖像輪廓,OpenCV Python,python,opencv,圖像處理

凸性檢測(cè)

  • cv2.isContourConvex() 可以可以用來(lái)檢測(cè)一個(gè)曲線是不是凸
    的。它只能返回 True 或 False。k = cv2.isContourConvex(cnt)
import numpy as np
import cv2
from matplotlib import pyplot as plt


# img = cv2.imread('./resource/opencv/image/Back_Projection_Theory2.jpg')
img = cv2.imread('./resource/opencv/image/shape.jpg')

gray = cv2.cvtColor(img.copy(), cv2.COLOR_BGR2GRAY)

# 二值化
(ret, thresh) = cv2.threshold(gray, 120, 255, cv2.THRESH_BINARY)
# (ret, thresh) = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
# thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 5, 2)

# 查找輪廓
(contours, his) = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

hull_img = img.copy()
for i in range(len(contours)):
    hull = cv2.convexHull(contours[i])
    isConvex = cv2.isContourConvex(contours[i])
    print(hull)
    print(isConvex)
    # 繪制凸包
    cv2.drawContours(hull_img, hull, -1, (0, 255, 0), 2)

# 繪制輪廓
contours = cv2.drawContours(img.copy(), contours, -1, (255, 0, 0), 2)


plt.subplot(231), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)), plt.title('img'), plt.xticks([]), plt.yticks([])
plt.subplot(232), plt.imshow(cv2.cvtColor(gray, cv2.COLOR_BGR2RGB)), plt.title('gray'), plt.xticks([]), plt.yticks([])
plt.subplot(233), plt.imshow(cv2.cvtColor(thresh, cv2.COLOR_BGR2RGB)), plt.title('thresh'), plt.xticks([]), plt.yticks([])
plt.subplot(234), plt.imshow(cv2.cvtColor(contours, cv2.COLOR_BGR2RGB)), plt.title('contours'), plt.xticks([]), plt.yticks([])
plt.subplot(235), plt.imshow(cv2.cvtColor(hull_img, cv2.COLOR_BGR2RGB)), plt.title('convex'), plt.xticks([]), plt.yticks([])
plt.show()

Python-OpenCV中的圖像處理-圖像輪廓,OpenCV Python,python,opencv,圖像處理

邊界矩形

邊界矩形有兩類(lèi):

  • 直邊界矩形
  • 旋轉(zhuǎn)邊界矩形

直邊界矩形

  • 直邊界矩形:一個(gè)直矩形(就是沒(méi)有旋轉(zhuǎn)的矩形)。它不會(huì)考慮對(duì)象是否旋轉(zhuǎn)。所以邊界矩形的面積不是最小的。可以使用函數(shù)
  • cv2.boundingRect() 函數(shù)獲取直邊界矩形。( x, y)為矩形左上角的坐標(biāo),( w, h)是矩形的寬和高。
    x,y,w,h = cv2.boundingRect(cnt)
    img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)

旋轉(zhuǎn)邊界矩形(最小面積矩形)

  • 旋轉(zhuǎn)的邊界矩形:這個(gè)邊界矩形是面積最小的,因?yàn)樗紤]了對(duì)象的旋轉(zhuǎn)。
  • cv2.minAreaRect()函數(shù)獲取旋轉(zhuǎn)邊界矩形。返回的是一個(gè) Box2D 結(jié)構(gòu),其中包含矩形中心點(diǎn)坐標(biāo)( x, y),矩形的寬和高( w, h),以及旋轉(zhuǎn)角度。
    (center(x,y), (width, height), angle of rotation) = cv2.minAreaRect(points)
  • cv2.boxPoints() 函數(shù)獲取旋轉(zhuǎn)邊界矩形的 4 個(gè)角點(diǎn)。
    [[x1, y1],[x2, y2], [x3, y3], [x4, y4]] = cv2.boxPoints(points)
import numpy as np
import cv2
from matplotlib import pyplot as plt

# 輪廓邊界矩形 分為兩種:直邊界矩形、旋轉(zhuǎn)邊界矩形

# 讀取圖像
img = cv2.imread('./resource/opencv/image/boundrect.jpg', cv2.IMREAD_COLOR)
draw = img.copy()

# 轉(zhuǎn)為灰度并二值化處理
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
(ret, thresh) = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
(contours, hierarchy) = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# 獲取直邊界矩形
x,y,w,h = cv2.boundingRect(contours[0])
print(x,y,w,h)
# 繪制直邊界矩形
draw = cv2.rectangle(draw, (x, y), (x+w, y+h), (0, 255, 0), 2)

# 獲取旋轉(zhuǎn)邊界矩形 獲取Box2D結(jié)構(gòu) (center(x,y), (width, height), angle of rotation)
box2d = cv2.minAreaRect(contours[0])
print(box2d)
# 獲取Box2D矩形4個(gè)角點(diǎn)坐標(biāo),[[x1, y1],[x2, y2], [x3, y3], [x4, y4]]
boxpoints = cv2.boxPoints(box2d)
print(boxpoints)
boxpoints = np.int32(boxpoints)
print(boxpoints[0])

# 畫(huà) 旋轉(zhuǎn)邊界矩形4個(gè)角點(diǎn)
draw = cv2.circle(draw, tuple(boxpoints[0]) , 3, (255, 0, 0), 2)
draw = cv2.circle(draw, tuple(boxpoints[1]) , 3, (255, 0, 0), 2)
draw = cv2.circle(draw, tuple(boxpoints[2]) , 3, (255, 0, 0), 2)
draw = cv2.circle(draw, tuple(boxpoints[3]) , 3, (255, 0, 0), 2)

# 畫(huà) 旋轉(zhuǎn)邊界矩形 矩形框
draw = cv2.line(draw, tuple(boxpoints[0]), tuple(boxpoints[1]), (0, 0, 255), 2)
draw = cv2.line(draw, tuple(boxpoints[1]), tuple(boxpoints[2]), (0, 0, 255), 2)
draw = cv2.line(draw, tuple(boxpoints[2]), tuple(boxpoints[3]), (0, 0, 255), 2)
draw = cv2.line(draw, tuple(boxpoints[3]), tuple(boxpoints[0]), (0, 0, 255), 2)

plt.subplot(131), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)), plt.title('original')
plt.subplot(132), plt.imshow(cv2.cvtColor(gray, cv2.COLOR_BGR2RGB)), plt.title('gray')
plt.subplot(133), plt.imshow(cv2.cvtColor(draw, cv2.COLOR_BGR2RGB)), plt.title('draw')
plt.show()

下圖"draw"標(biāo)題的圖片綠色矩形是輪廓的直邊界矩形,紅色矩形是輪廓的旋轉(zhuǎn)邊界矩形(最小面積矩形),藍(lán)色的4個(gè)點(diǎn)是旋轉(zhuǎn)邊界矩形的四個(gè)角點(diǎn):
Python-OpenCV中的圖像處理-圖像輪廓,OpenCV Python,python,opencv,圖像處理

最小外接圓

  • 能包括對(duì)象所有的圓中面積最小的一個(gè)。
  • cv2.minEnclosingCircle() 獲取最小外接圓
    (x,y),radius = cv2.minEnclosingCircle(cnt)
import numpy as np
import cv2
from matplotlib import pyplot as plt

# 讀取圖像
img = cv2.imread('./resource/opencv/image/boundrect.jpg', cv2.IMREAD_COLOR)

# 轉(zhuǎn)為灰度并二值化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
(ret, thresh) = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

# 查找對(duì)象輪廓
(contours, hierarchy) = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# 根據(jù)輪廓查找對(duì)象最小外接圓
(x,y), radius = cv2.minEnclosingCircle(contours[0])
print((x,y), radius)

# 畫(huà) 對(duì)象最小外接圓
img = cv2.circle(img, (int(x), int(y)), int(radius), (0, 0, 255), 1)

# 顯示圖像
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Python-OpenCV中的圖像處理-圖像輪廓,OpenCV Python,python,opencv,圖像處理

最小外接三角

  • 能包括對(duì)象所有的三角形中面積最小的一個(gè)。
  • cv2.minEnclosingTriangle():返回 area, [[[x1, y1]],[[x2, y2]], [[x3, y3]]]
    area, triangle = cv2.minEnclosingTriangle(points)
import numpy as np
import cv2

# 讀取圖像
img = cv2.imread('./resource/opencv/image/boundrect.jpg', cv2.IMREAD_COLOR)

# 轉(zhuǎn)為灰度并做二值化處理
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
(ret, thresh) = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

# 查找輪廓
(contours, hierarchy) = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# 根據(jù)輪廓獲取對(duì)象的最小外接三角, area, [[[x1, y1]],[[x2, y2]], [[x3, y3]]]
area, triangle = cv2.minEnclosingTriangle(contours[0])
print(area)
print(triangle)

# 最小外接三角的3個(gè)角點(diǎn)坐標(biāo)轉(zhuǎn)為整型(獲取到的是浮點(diǎn)型,不能用于圖形繪制)
triangle = np.int32(triangle)
print(triangle[0][0])
print(triangle[1][0])
print(triangle[2][0])

# 繪制最小外接三角
img = cv2.line(img, tuple(triangle[0][0]), tuple(triangle[1][0]), (0, 0, 255), 2)
img = cv2.line(img, tuple(triangle[1][0]), tuple(triangle[2][0]), (0, 0, 255), 2)
img = cv2.line(img, tuple(triangle[2][0]), tuple(triangle[0][0]), (0, 0, 255), 2)

# 顯示圖像
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Python-OpenCV中的圖像處理-圖像輪廓,OpenCV Python,python,opencv,圖像處理

橢圓擬合

  • cv2.ellipse(),返回值其實(shí)就是旋轉(zhuǎn)邊界矩形的內(nèi)切圓
import numpy as np
import cv2

img = cv2.imread('./resource/opencv/image/boundrect.jpg', cv2.IMREAD_COLOR)

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
(ret, thresh) = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

(contuors, hierarchy) = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

ellipse1 = cv2.fitEllipse(contuors[0])
ellipse2 = cv2.fitEllipseAMS(contuors[0])
ellipse3 = cv2.fitEllipseDirect(contuors[0])
print(ellipse1)
print(ellipse2)
print(ellipse3)

img = cv2.ellipse(img, ellipse1, (255, 0, 0), 3)
img = cv2.ellipse(img, ellipse2, (0, 255, 0), 2)
img = cv2.ellipse(img, ellipse3, (0, 0, 255), 1)

cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Python-OpenCV中的圖像處理-圖像輪廓,OpenCV Python,python,opencv,圖像處理

直線擬合

  • 根據(jù)一組點(diǎn)擬合出一條直線,同樣也可以為圖像中的白色點(diǎn)擬合出一條直線。
import numpy as np
import cv2

img = cv2.imread('./resource/opencv/image/boundrect.jpg', cv2.IMREAD_COLOR)

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
(ret, thresh) = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

(contuors, hierarchy) = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# 獲取并繪制 直線擬合,直接繪制獲取的坐標(biāo)只有一半的線段
L = cv2.fitLine(contuors[0], cv2.DIST_L2, 0, 0.01, 0.01)
L = np.int32(L)
img = cv2.line(img, (L[0][0], L[1][0]), (L[2][0], L[3][0]), (0, 0, 255), 2)


# 獲取并繪制 計(jì)算出整幅圖的直線擬合線
rows, cols = img.shape[:2]
[vx,vy,x,y] = cv2.fitLine(contuors[0], 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)


cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Python-OpenCV中的圖像處理-圖像輪廓,OpenCV Python,python,opencv,圖像處理

輪廓的性質(zhì)

長(zhǎng)寬比

邊界矩形的長(zhǎng)寬比:
A s p e c t R a t i o n = W i d t h H e i g h t Aspect Ration = \frac{Width}{Height} AspectRation=HeightWidth?
x,y,w,h = cv2.boundingRect(points)
aspect_ratio = float(w)/h

輪廓面積與邊界矩形面積的比(Extent)

輪廓面積與邊界矩形面積的比:
E x t e n t = O b j e c t A r e a B o u n d i n g R e c t a n g l e A r e a Extent = \frac{Object Area}{Bounding Rectangle Area} Extent=BoundingRectangleAreaObjectArea?

area = cv2.contourArea(cnt)
x,y,w,h = cv2.boundingRect(cnt)
rect_area = w*h
extent = float(area)/rect_area

輪廓面積與凸包面積的比(Solidity)

輪廓面積與凸包面積的比:
S o l i d i t y = C o n t o u r A r e a C o n v e x H u l l A r e a Solidity= \frac{Contour Area}{Convex Hull Area} Solidity=ConvexHullAreaContourArea?

area = cv2.contourArea(cnt)
hull = cv2.convexHull(cnt)
hull_area = cv2.contourArea(hull)
solidity = float(area)/hull_area

與輪廓面積相等的圓形的直徑(Equivalent Diameter)

與輪廓面積相等的圓形的直徑:
E q u i v a l e n t D i a m e t e r = 4 ? C o n t o u r A r e a π Equivalent Diameter = \sqrt{\frac{4*Contour Area}{\pi}} EquivalentDiameter=π4?ContourArea? ?

area = cv2.contourArea(cnt)
equi_diameter = np.sqrt(4*area/np.pi)

輪廓對(duì)象的方向

  • (x,y),(MA,ma),angle = cv2.fitEllipse(cnt)
  • 返回中心坐標(biāo),長(zhǎng)軸和短軸的長(zhǎng)度,對(duì)象的方向。

輪廓的掩模和像素點(diǎn)

有時(shí)我們需要構(gòu)成對(duì)象的所有像素點(diǎn):

mask = np.zeros(imgray.shape,np.uint8)
這里一定要使用參數(shù)-1, 繪制填充的的輪廓
cv2.drawContours(mask,[cnt],0,255,-1)
pixelpoints = np.transpose(np.nonzero(mask))

pixelpoints = cv2.findNonZero(mask)

最大值和最小值及它們的位置

可以使用掩模圖像得到這些參數(shù):

min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(imgray,mask = mask)

平均顏色及平均灰度

可以使用相同的掩模求一個(gè)對(duì)象的平均顏色或平均灰度:

mean_val = cv2.mean(im,mask = mask)

對(duì)象輪廓的極點(diǎn)

  • 一個(gè)對(duì)象最上面,最下面,最左邊,最右邊的點(diǎn)。

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])

Python-OpenCV中的圖像處理-圖像輪廓,OpenCV Python,python,opencv,圖像處理

輪廓的凸缺陷

  • cv.convexityDefect()以幫助我們找到凸缺陷。函數(shù)調(diào)用如下:
    hull = cv2.convexHull(cnt,returnPoints = False)
    defects = cv2.convexityDefects(cnt,hull)
    它會(huì)返回一個(gè)數(shù)組,其中每一行包含的值是 [起點(diǎn),終點(diǎn),最遠(yuǎn)的點(diǎn),到最遠(yuǎn)點(diǎn)的近似距離]。我們可以在一張圖上顯示它。我們將起點(diǎn)和終點(diǎn)用一條綠線連接,在最遠(yuǎn)點(diǎn)畫(huà)一個(gè)圓圈,要記住的是返回結(jié)果的前三個(gè)值是輪廓點(diǎn)的索引。所以我們還要到輪廓點(diǎn)中去找它們。
import numpy as np
import cv2

img = cv2.imread('./resource/opencv/image/shape.jpg', cv2.IMREAD_COLOR)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

(ret, thresh) = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
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()

Python-OpenCV中的圖像處理-圖像輪廓,OpenCV Python,python,opencv,圖像處理

點(diǎn)到輪廓的最短距離

求解一個(gè)點(diǎn)到輪廓的最短距離:

  • dist = cv2.pointPolygonTest(contours[0], (20, 20), True)
    measureDist=True,返回結(jié)果:
    小于零:點(diǎn)在輪廓外部。
    等于零:點(diǎn)在輪廓線上。
    大于零:點(diǎn)在輪廓內(nèi)部。
  • stat = cv2.pointPolygonTest(contours[0], (20, 20), False)
    measureDist=False,返回結(jié)果:
    -1:點(diǎn)在輪廓外部
    0:點(diǎn)在輪廓線上。
    1:點(diǎn)在輪廓內(nèi)部。
import numpy as np
import cv2

img = cv2.imread('./resource/opencv/image/shape.jpg', cv2.IMREAD_COLOR)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

(ret, thresh) = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
(contours, hierarchy) = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# 求解圖像中的一個(gè)點(diǎn)到一個(gè)對(duì)象輪廓的最短距離。
# 小于零:點(diǎn)在輪廓外部。
# 等于零:點(diǎn)在輪廓線上。
# 大于零:點(diǎn)在輪廓內(nèi)部。
dist = cv2.pointPolygonTest(contours[0], (20, 20), True)

#-1:點(diǎn)在輪廓外部
# 0:點(diǎn)在輪廓線上。
# 1:點(diǎn)在輪廓內(nèi)部。
stat = cv2.pointPolygonTest(contours[0], (20, 20), False)

print(dist)
print(stat)

形狀匹配

  • match = cv2.matchShapes(cntA, cntB, cv2.CONTOURS_MATCH_I1, 0.0)
    返回值越小表示兩個(gè)圖形越相似。

有3中匹配方法:

  1. cv2.CONTOURS_MATCH_I1
  2. cv2.CONTOURS_MATCH_I2
  3. cv2.CONTOURS_MATCH_I3
import numpy as np
import cv2
from matplotlib import pyplot as plt



img = cv2.imread('./resource/opencv/image/matchshapesA.jpg', cv2.IMREAD_COLOR)
imgA = cv2.imread('./resource/opencv/image/matchshapesA.jpg', cv2.IMREAD_COLOR)
imgB = cv2.imread('./resource/opencv/image/matchshapesB.jpg', cv2.IMREAD_COLOR)
imgC = cv2.imread('./resource/opencv/image/matchshapesC.jpg', cv2.IMREAD_COLOR)

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
grayA = cv2.cvtColor(imgA, cv2.COLOR_BGR2GRAY)
grayB = cv2.cvtColor(imgB, cv2.COLOR_BGR2GRAY)
grayC = cv2.cvtColor(imgC, cv2.COLOR_BGR2GRAY)

(ret, th) = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
(retA, thA) = cv2.threshold(grayA, 127, 255, cv2.THRESH_BINARY)
(retB, thB) = cv2.threshold(grayB, 127, 255, cv2.THRESH_BINARY)
(retC, thC) = cv2.threshold(grayC, 127, 255, cv2.THRESH_BINARY)

(contours, hierarchy) = cv2.findContours(th, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
(contoursA, hierarchyA) = cv2.findContours(thA, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
(contoursB, hierarchyB) = cv2.findContours(thB, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
(contoursC, hierarchyC) = cv2.findContours(thC, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

cnt = contours[0]
cntA = contoursA[0]
cntB = contoursB[0]
cntC = contoursC[0]

m1 = cv2.matchShapes(cnt, cntA, cv2.CONTOURS_MATCH_I1, 0.0)
m2 = cv2.matchShapes(cnt, cntB, cv2.CONTOURS_MATCH_I1, 0.0)
m3 = cv2.matchShapes(cnt, cntC, cv2.CONTOURS_MATCH_I1, 0.0)

# 程序運(yùn)行結(jié)果
print(m1) # A與A的匹配度:0.0
print(m2) # A與B的匹配度:0.010547834665352251
print(m3) # A與C的匹配度:0.3313932685758914

從結(jié)果可以看出兩個(gè)圖形越相似值就越小,計(jì)算結(jié)果和圖形的旋轉(zhuǎn)相關(guān)性小,和圖形的形狀差異相關(guān)性大:
Python-OpenCV中的圖像處理-圖像輪廓,OpenCV Python,python,opencv,圖像處理

輪廓的層次結(jié)構(gòu)

(contours, hierarchy) = cv2.findContours(th, mode, method)
輪廓的檢索模式mode有如下幾種:

  • cv2.RETR_LIST:只是提取所有的輪廓,而不去創(chuàng)建任何父子關(guān)系。換句話說(shuō)就是“人人平等”,所有輪廓屬于同一級(jí)組織輪廓。

  • cv2.RETR_TREE:返回所有輪廓,并且創(chuàng)建一個(gè)完整的組織結(jié)構(gòu)列表。它甚至?xí)嬖V你誰(shuí)是爺爺,爸爸,兒子,孫子等。

  • cv2.RETR_CCOMP:返回所有的輪廓并將輪廓分為兩級(jí)組織結(jié)構(gòu)。

  • cv2.RETR_EXTERNAL:只會(huì)返回最外邊的的輪廓,所有的子輪廓都會(huì)被忽略掉。

  • 不管層次結(jié)構(gòu)是什么樣的,每一個(gè)輪廓都包含自己的信息:誰(shuí)是父,誰(shuí)是子等。 OpenCV 使用一個(gè)含有四個(gè)元素的數(shù)組表示。 [Next, Previous,F(xiàn)irst_Child, Parent]。

  • Next 表示同一級(jí)組織結(jié)構(gòu)中的下一個(gè)輪廓。以下圖中的輪廓 0 為例,輪廓 1 就是他的 Next。同樣,輪廓 1 的 Next是 2, Next=2。那輪廓 2 呢?在同一級(jí)沒(méi)有 Next。這時(shí) Next=-1。而輪廓 4 的 Next為 5,所以它的 Next=5。

  • Previous 表示同一級(jí)結(jié)構(gòu)中的前一個(gè)輪廓。與前面一樣,輪廓 1 的 Previous 為輪廓 0,輪廓 2 的 Previous 為輪廓 1。輪廓 0 沒(méi)有 Previous,所以 Previous=-1。

  • First_Child 表示它的第一個(gè)子輪廓。沒(méi)有必要再解釋了,輪廓 2 的子輪廓為 2a。所以它的 First_Child 為2a。那輪廓 3a 呢?它有兩個(gè)子輪廓。但是我們只要第一個(gè)子輪廓,所以是輪廓 4(按照從上往下,從左往右的順序排序)。

  • Parent 表示它的父輪廓。與 First_Child 剛好相反。輪廓 4 和 5 的父輪廓是輪廓 3a。而輪廓 3a的父輪廓是 3。

輪廓的層次結(jié)構(gòu),比如輪廓之間的父子關(guān)系:
Python-OpenCV中的圖像處理-圖像輪廓,OpenCV Python,python,opencv,圖像處理
在這幅圖像中,給這幾個(gè)形狀編號(hào)為 0-5。 2 和 2a 分別代表最外邊矩形
的外輪廓和內(nèi)輪廓。在這里邊輪廓 0, 1, 2 在外部或最外邊。我們可以稱他們?yōu)椋ńM織結(jié)構(gòu))0 級(jí),簡(jiǎn)單來(lái)說(shuō)就是他們屬于同一級(jí)。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-645466.html

到了這里,關(guān)于Python-OpenCV中的圖像處理-圖像輪廓的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Python-OpenCV中的圖像處理-圖像金字塔

    Python-OpenCV中的圖像處理-圖像金字塔

    同一圖像的不同分辨率的子圖集合,如果把最大的圖像放在底部,最小的放在頂部,看起來(lái)像一座金字塔,故而得名圖像金字塔。 cv2.pyrUp():上采樣 cv2.pyrDown():下采樣 高斯金字塔的頂部是通過(guò)將底部圖像中的連續(xù)的行和列去除得到的。頂部圖像中的每個(gè)像素值等于下一層圖

    2024年02月13日
    瀏覽(22)
  • Python-OpenCV中的圖像處理-幾何變換

    Python-OpenCV中的圖像處理-幾何變換

    對(duì)圖像進(jìn)行各種幾個(gè)變換,例如移動(dòng),旋轉(zhuǎn),仿射變換等。 cv2.resize() cv2.INTER_AREA v2.INTER_CUBIC v2.INTER_LINEAR res = cv2.resize(img, None, fx=2, fy=2, interpolation=cv2.INTER_CUBIC) 或 height, width = img.shape[:2] res = cv2.resize(img, (2 width, 2 height), interpolation=cv2.INTER_CUBIC) OpenCV提供了使用函數(shù)cv2.warpAffine()實(shí)

    2024年02月13日
    瀏覽(97)
  • Python-OpenCV中的圖像處理-物體跟蹤

    Python-OpenCV中的圖像處理-物體跟蹤

    現(xiàn)在我們知道怎樣將一幅圖像從 BGR 轉(zhuǎn)換到 HSV 了,我們可以利用這一點(diǎn)來(lái)提取帶有某個(gè)特定顏色的物體。在 HSV 顏色空間中要比在 BGR 空間中更容易表示一個(gè)特定顏色。在我們的程序中,我們要提取的是一個(gè)藍(lán)色的物體。下面就是就是我們要做的幾步: ? 從視頻中獲取每一幀

    2024年02月13日
    瀏覽(22)
  • Python-OpenCV中的圖像處理-邊緣檢測(cè)

    Python-OpenCV中的圖像處理-邊緣檢測(cè)

    Canny 邊緣檢測(cè)是一種非常流行的邊緣檢測(cè)算法,是 John F.Canny 在 1986 年提出的。它是一個(gè)有很多步構(gòu)成的算法:噪聲去除、計(jì)算圖像梯度、非極大值抑制、滯后閥值等。 Canny(image: Mat, threshold1, threshold2, edges=…, apertureSize=…, L2gradient=…) 在 OpenCV 中只需要一個(gè)函數(shù): cv2.Canny(),

    2024年02月13日
    瀏覽(35)
  • Python-OpenCV中的圖像處理-霍夫變換

    Python-OpenCV中的圖像處理-霍夫變換

    霍夫(Hough)變換在檢測(cè)各種形狀的技術(shù)中非常流行,如果要檢測(cè)的形狀可以用數(shù)學(xué)表達(dá)式描述,就可以是使用霍夫變換檢測(cè)它。即使要檢測(cè)的形狀存在一點(diǎn)破壞或者扭曲也是可以使用。 Hough直線變換,可以檢測(cè)一張圖像中的直線 cv2.HoughLines(image, rho, theta, threshold) return:返回值

    2024年02月13日
    瀏覽(124)
  • Python-OpenCV中的圖像處理-直方圖

    Python-OpenCV中的圖像處理-直方圖

    通過(guò)直方圖你可以對(duì)整幅圖像的灰度分布有一個(gè)整體的了解。直方圖的 x 軸是灰度值( 0 到 255), y 軸是圖片中具有同一個(gè)灰度的點(diǎn)的數(shù)目。 BINS:上面的直方圖顯示了每個(gè)灰度值對(duì)應(yīng)的像素?cái)?shù)。如果像素值為 0到255,你就需要 256 個(gè)數(shù)來(lái)顯示上面的直方圖。但是,如果你不需

    2024年02月13日
    瀏覽(30)
  • Python-OpenCV中的圖像處理-顏色空間轉(zhuǎn)換

    Python-OpenCV中的圖像處理-顏色空間轉(zhuǎn)換

    在 OpenCV 中有超過(guò) 150 中進(jìn)行顏色空間轉(zhuǎn)換的方法。但是你以后就會(huì) 發(fā)現(xiàn)我們經(jīng)常用到的也就兩種: BGR G r a y 和 B G R Gray 和 BGR G r a y 和 BGR HSV。 注意:在 OpenCV 的 HSV 格式中, H(色彩/色度)的取值范圍是 [0, 179],S(飽和度)的取值范圍 [0, 255], V(亮度)的取值范圍 [0,

    2024年02月13日
    瀏覽(25)
  • Python-OpenCV中的圖像處理-形態(tài)學(xué)轉(zhuǎn)換

    Python-OpenCV中的圖像處理-形態(tài)學(xué)轉(zhuǎn)換

    形態(tài)學(xué)操作:腐蝕,膨脹,開(kāi)運(yùn)算,閉運(yùn)算,形態(tài)學(xué)梯度,禮帽,黑帽等 主要涉及函數(shù):cv2.erode(), cv2.dilate(), cv2.morphologyEx() 原理:形態(tài)學(xué)操作是根據(jù)圖像形狀進(jìn)行的簡(jiǎn)單操作。一般情況下對(duì)二值化圖像進(jìn)行的操作。需要輸入兩個(gè)參數(shù),一個(gè)是原始圖像,第二個(gè)被稱為結(jié)構(gòu)化

    2024年02月13日
    瀏覽(24)
  • Python-OpenCV中的圖像處理-傅里葉變換

    Python-OpenCV中的圖像處理-傅里葉變換

    傅里葉變換經(jīng)常被用來(lái)分析不同濾波器的頻率特性。我們可以使用 2D 離散傅里葉變換 (DFT) 分析圖像的頻域特性。實(shí)現(xiàn) DFT 的一個(gè)快速算法被稱為快速傅里葉變換( FFT)。 對(duì)于一個(gè)正弦信號(hào):x (t) = A sin (2πft), 它的頻率為 f,如果把這個(gè)信號(hào)轉(zhuǎn)到它的頻域表示,我們會(huì)在頻率

    2024年02月12日
    瀏覽(22)
  • Python-OpenCV中的圖像處理-GrabCut算法交互式前景提取

    Python-OpenCV中的圖像處理-GrabCut算法交互式前景提取

    cv2.grabCut(img: Mat, mask: typing.Optional[Mat], rect, bgdModel, fgdModel, iterCount, mode=…) img:輸入圖像 mask:掩模圖像,用來(lái)確定那些區(qū)域是背景,前景,可能是前景/背景等。 可以設(shè)置為: cv2.GC_BGD,cv2.GC_FGD,cv2.GC_PR_BGD,cv2.GC_PR_FGD,或者直接輸入 0,1,2,3 也行。 rect :包含前景的矩形,格式為

    2024年02月13日
    瀏覽(104)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包