小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

OpenCV實戰(zhàn)(1)

 wuxinit_ 2021-02-03

如果需要處理的原圖及代碼,請移步小編的GitHub地址

  傳送門:請點擊我

  如果點擊有誤:https://github.com/LeBron-Jian/ComputerVisionPractice

  最近一段時間學習并做的都是對圖像進行處理,其實自己也是新手,各種嘗試,所以我這個門外漢想總結(jié)一下自己學習的東西,圖像處理的流程。但是動起筆來想總結(jié),一下卻不知道自己要寫什么,那就把自己做過的相似圖片搜索的流程整理一下,想到什么說什么吧。

一:圖片相似度算法(對像素求方差并比對)的學習

1.1 算法邏輯

1.1.1  縮放圖片

  將需要處理的圖片所放到指定尺寸,縮放后圖片大小由圖片的信息量和復(fù)雜度決定。譬如,一些簡單的圖標之類圖像包含的信息量少,復(fù)雜度低,可以縮放小一點。風景等復(fù)雜場景信息量大,復(fù)雜度高就不能縮放太小,容易丟失重要信息。根據(jù)自己需求,彈性的縮放。在效率和準確度之間維持平衡。

1.1.2  灰度處理

  通常對比圖像相似度和顏色關(guān)系不是很大,所以處理為灰度圖,減少后期計算的復(fù)雜度。如果有特殊需求則保留圖像色彩。

1.1.3 計算平均值

  此處開始,與傳統(tǒng)的哈希算法不同:分別依次計算圖像每行像素點的平均值,記錄每行像素點的平均值。每一個平均值對應(yīng)著一行的特征。

1.1.4  計算方差

  對得到的所有平均值進行計算方差,得到的方差就是圖像的特征值。方差可以很好的反應(yīng)每行像素特征的波動,既記錄了圖片的主要信息。

1.1.5  比較方差

  經(jīng)過上面的計算之后,每張圖都會生成一個特征值(方差)。到此,比較圖像相似度就是比較圖像生成方差的接近成程度。
  一組數(shù)據(jù)方差的大小可以判斷穩(wěn)定性,多組數(shù)據(jù)方差的接近程度可以反應(yīng)數(shù)據(jù)波動的接近程度。我們不關(guān)注方差的大小,只關(guān)注兩個方差的差值的大小。方差差值越小圖像越相似!

 

1.2  代碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import cv2
import matplotlib.pyplot as plt
#計算方差
def getss(list):
    #計算平均值
    avg=sum(list)/len(list)
    #定義方差變量ss,初值為0
    ss=0
    #計算方差
    for l in list:
        ss+=(l-avg)*(l-avg)/len(list)
    #返回方差
    return ss
#獲取每行像素平均值
def getdiff(img):
    #定義邊長
    Sidelength=30
    #縮放圖像
    img=cv2.resize(img,(Sidelength,Sidelength),interpolation=cv2.INTER_CUBIC)
    #灰度處理
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    #avglist列表保存每行像素平均值
    avglist=[]
    #計算每行均值,保存到avglist列表
    for i in range(Sidelength):
        avg=sum(gray[i])/len(gray[i])
        avglist.append(avg)
    #返回avglist平均值
    return avglist
#讀取測試圖片
img1=cv2.imread("james.jpg")
diff1=getdiff(img1)
print('img1:',getss(diff1))
#讀取測試圖片
img11=cv2.imread("durant.jpg")
diff11=getdiff(img11)
print('img11:',getss(diff11))
ss1=getss(diff1)
ss2=getss(diff11)
print("兩張照片的方差為:%s"%(abs(ss1-ss2)))
x=range(30)
plt.figure("avg")
plt.plot(x,diff1,marker="*",label="$jiames$")
plt.plot(x,diff11,marker="*",label="$durant$")
plt.title("avg")
plt.legend()
plt.show()
cv2.waitKey(0)
cv2.destroyAllWindows()

   兩張原圖:

 

  圖像結(jié)果如下:

1
2
3
img1: 357.03162469135805
img11: 202.56193703703704
兩張照片的方差為:154.469687654321

 

   實驗環(huán)境開始設(shè)置了圖片像素值,而且進行灰度化處理,此方法比對圖像相似對不同的圖片方差很大,結(jié)果很明顯,但是對比比較相似,特別相似的圖片不適應(yīng)。

二:圖片相似度算法(感知哈希算法)的學習

  "感知哈希算法"(Perceptual hash algorithm),它的作用是對每張圖片生成一個"指紋"(fingerprint)字符串,然后比較不同圖片的指紋。結(jié)果越接近,就說明圖片越相似。

2.1  算法步驟

2.1.1 縮小尺寸

  將圖片縮小到8x8的尺寸,總共64個像素。這一步的作用是去除圖片的細節(jié),只保留結(jié)構(gòu)、明暗等基本信息,摒棄不同尺寸、比例帶來的圖片差異。

2.1.2  簡化色彩

  將縮小后的圖片,轉(zhuǎn)為64級灰度。也就是說,所有像素點總共只有64種顏色。

2.1.3  計算平均值

  計算所有64個像素的灰度平均值

2.1.4  比較像素的灰度平均值

  將每個像素的灰度,與平均值進行比較。大于或等于平均值,記為1;小于平均值,記為0。

2.1.5 計算哈希值

  將上一步的比較結(jié)果,組合在一起,就構(gòu)成了一個64位的整數(shù),這就是這張圖片的指紋。組合的次序并不重要,只要保證所有圖片都采用同樣次序就行了。

  得到指紋以后,就可以對比不同的圖片,看看64位中有多少位是不一樣的。在理論上,這等同于計算"漢明距離"(Hamming distance)。如果不相同的數(shù)據(jù)位不超過5,就說明兩張圖片很相似;如果大于10,就說明這是兩張不同的圖片。

1
2
3
4
    此算法參考博客:http://www.ruanyifeng.com/blog/2011/07
    /principle_of_similar_image_search.html
     
但是未實現(xiàn)代碼,代碼如下:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#!/usr/bin/python
import glob
import os
import sys
from PIL import Image
EXTS = 'jpg', 'jpeg', 'JPG', 'JPEG', 'gif', 'GIF', 'png', 'PNG'
def avhash(im):
    if not isinstance(im, Image.Image):
        im = Image.open(im)
    im = im.resize((8, 8), Image.ANTIALIAS).convert('L')
    avg = reduce(lambda x, y: x + y, im.getdata()) / 64.
    return reduce(lambda x, (y, z): x | (z << y),
                  enumerate(map(lambda i: 0 if i < avg else 1, im.getdata())),
                  0)
def hamming(h1, h2):
    h, d = 0, h1 ^ h2
    while d:
        h += 1
        d &= d - 1
    return h
if __name__ == '__main__':
    if len(sys.argv) <= 1 or len(sys.argv) > 3:
        print "Usage: %s image.jpg [dir]" % sys.argv[0]
    else:
        im, wd = sys.argv[1], '.' if len(sys.argv) < 3 else sys.argv[2]
        h = avhash(im)
        os.chdir(wd)
        images = []
        for ext in EXTS:
            images.extend(glob.glob('*.%s' % ext))
        seq = []
        prog = int(len(images) > 50 and sys.stdout.isatty())
        for f in images:
            seq.append((f, hamming(avhash(f), h)))
            if prog:
                perc = 100. * prog / len(images)
                x = int(2 * perc / 5)
                print '\rCalculating... [' + '#' * x + ' ' * (40 - x) + ']',
                print '%.2f%%' % perc, '(%d/%d)' % (prog, len(images)),
                sys.stdout.flush()
                prog += 1
        if prog: print
        for f, ham in sorted(seq, key=lambda i: i[1]):
            print "%d\t%s" % (ham, f)

 

 

三:模板匹配

3.1  模板匹配的定義

  模板就是一幅已知的小圖像,而模板匹配就是在一幅大圖像中搜尋目標,已知該圖中有要找的目標,且該目標與模板有相同的尺度,方向和圖像元素,通過一定的算法可以在圖像中找到目標。

  模板匹配和卷積原理很像,模板在原圖像上開始滑動,計算模板與圖像被模板覆蓋的地方的差別程度,這個差別程度的計算方法在opencv里有6種,然后將每次計算的結(jié)果放入一個矩陣里,作為結(jié)果輸出。假如原圖像是A*B大小,而模板是 a*b大小,則輸出結(jié)果的矩陣是 (A-a+1)*(B-b+1)。

3.2  模板匹配方法

  模板匹配在opencv中的函數(shù)為 cv2.matchTemplate(),下面看一下其源碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def matchTemplate(image, templ, method, result=None, mask=None): # real signature unknown; restored from __doc__
    """
    matchTemplate(image, templ, method[, result[, mask]]) -> result
    .   @brief Compares a template against overlapped image regions.
    .  
    .   The function slides through image , compares the overlapped patches of size \f$w \times h\f$ against
    .   templ using the specified method and stores the comparison results in result . Here are the formulae
    .   for the available comparison methods ( \f$I\f$ denotes image, \f$T\f$ template, \f$R\f$ result ). The summation
    .   is done over template and/or the image patch: \f$x' = 0...w-1, y' = 0...h-1\f$
    .  
    .   After the function finishes the comparison, the best matches can be found as global minimums (when
    .   #TM_SQDIFF was used) or maximums (when #TM_CCORR or #TM_CCOEFF was used) using the
    .   #minMaxLoc function. In case of a color image, template summation in the numerator and each sum in
    .   the denominator is done over all of the channels and separate mean values are used for each channel.
    .   That is, the function can take a color template and a color image. The result will still be a
    .   single-channel image, which is easier to analyze.
    .  
    .   @param image Image where the search is running. It must be 8-bit or 32-bit floating-point.
    .   @param templ Searched template. It must be not greater than the source image and have the same
    .   data type.
    .   @param result Map of comparison results. It must be single-channel 32-bit floating-point. If image
    .   is \f$W \times H\f$ and templ is \f$w \times h\f$ , then result is \f$(W-w+1) \times (H-h+1)\f$ .
    .   @param method Parameter specifying the comparison method, see #TemplateMatchModes
    .   @param mask Mask of searched template. It must have the same datatype and size with templ. It is
    .   not set by default. Currently, only the #TM_SQDIFF and #TM_CCORR_NORMED methods are supported.
    """
    pass

   下面對模板匹配方法進行解釋:

  • cv2.TM_CCOEFF:系數(shù)匹配法,計算相關(guān)系數(shù),計算出來的值越大,越相關(guān)
  • cv2.TM_CCOEFF_NORMED:相關(guān)系數(shù)匹配法,計算歸一化相關(guān)系數(shù),計算出來的值越接近1,越相關(guān)
  • cv2.TM_CCORR:相關(guān)匹配法,計算相關(guān)性,計算出來的值越大,越相關(guān)
  • cv2.TM_CCORR_NORMED:歸一化相關(guān)匹配法,計算歸一化相關(guān)性,計算出來的值越接近1,越相關(guān)
  • cv2.TM_SQDIFF:平方差匹配法,計算平方不同,計算出來的值越小,越相關(guān)
  • cv2.TM_SQDIFF_NORMED:歸一化平方差匹配法,計算歸一化平方不同,計算出來的值越接近0,越相關(guān)

  公式復(fù)制opencv官網(wǎng),如下:

   下面實操一下。

3.2  模板匹配一個對象實例

  原圖是lena.jpg,模板是lena的臉,均可以去我GitHub上拿。

  代碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#_*_coding:utf-8_*_
import cv2
import numpy as np
import matplotlib.pyplot as plt
   
img_path = 'lena.jpg'
img = cv2.imread(img_path, 0)
template = cv2.imread('face.jpg', 0)
template_h, template_w = template.shape[:2]
print(img.shape)   # (263, 263)
print(template.shape)  # (110, 85)
methods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR',
            'cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED']
res = cv2.matchTemplate(img, template, cv2.TM_SQDIFF)
# 函數(shù)返回值就是矩陣的最小值,最大值,最小值的索引,最大值的索引。
min_val, max_val, min_index, max_index = cv2.minMaxLoc(res)
# print(min_val, max_val, min_index, max_index)
# 39168.0  74403584.0 (107, 89) (159, 62)
for meth in methods:
    img2 = img.copy()
    # 匹配方法的真值
    method = eval(meth)
    # print(meth, method)
    '''
        cv2.TM_CCOEFF 4
        cv2.TM_CCOEFF_NORMED 5
        cv2.TM_CCORR 2
        cv2.TM_CCORR_NORMED 3
        cv2.TM_SQDIFF 0
        cv2.TM_SQDIFF_NORMED 1
    '''
    res = cv2.matchTemplate(img, template, method)
    # 函數(shù)返回值就是矩陣的最小值,最大值,最小值的索引,最大值的索引。
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
    # 如果是平方差匹配 TM_SQDIFF 或歸一化平方差匹配 TM_SQDIFF_NORMED,取最小值
    if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
        top_left = min_loc
    else:
        top_left = max_loc
    bottom_right = (top_left[0] + template_w, top_left[1] + template_h)
    # 畫矩形
    cv2.rectangle(img2, top_left, bottom_right, 255, 2)
    plt.subplot(121), plt.imshow(res, cmap='gray')
    plt.xticks([]), plt.yticks([])  # 隱藏坐標軸
    plt.subplot(122), plt.imshow(img2, cmap='gray')
    plt.xticks([]), plt.yticks([])
    plt.suptitle(meth)
    plt.show()

   效果如下:

3.3  模板匹配多個對象

  有時候,你需要匹配的模板在圖像中多次出現(xiàn),那么就需要多對象匹配。多對象匹配的原理很簡單,因為opencv里的模板匹配里的每一處和模板進行對比,所以同一個模板下,多對象匹配情況下,結(jié)果矩陣里會有好幾個值,和最大(?。┲到咏?,如果我們設(shè)置一個閾值,在這個閾值以上(以下)的值都提取出來,再分別得到他們的坐標,理論上只要這個閾值設(shè)置的恰當,就可以將多對象都匹配出來。

  原圖是超級瑪麗的一張截圖,模板是金幣,也可以去我GitHub上拿。

  這種方法的方框要 粗一點,因為我們定義的 threshold 為 0.8,(只針對代碼中的 cv2.TM_CCOEFF_NORMED 匹配方法),loc檢測出來有 9個點,相當于畫了三次框,所以要粗一點。

  代碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#_*_coding:utf-8_*_
import cv2
import numpy as np
import matplotlib.pyplot as plt
   
img_path = 'mario.jpg'
img_rgb = cv2.imread(img_path)
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread('mario_coin.jpg', 0)
template_h, template_w = template.shape[:2]
print(img_gray.shape)   # (207, 225)
print(template.shape)  # (27, 16)
res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
threshold = 0.8
# 取匹配程度大于 80% 的坐標
loc = np.where(res >= threshold)
for pt in zip(*loc[::-1]):  # *表示可選參數(shù)
    bottom_right = (pt[0] + template_w, pt[1] + template_h)
    cv2.rectangle(img_rgb, pt, bottom_right, (0, 0, 255), 2)
cv2.imshow('img_rgb', img_rgb)
cv2.waitKey(0)
cv2.destroyAllWindows()

  效果如下:

 

 3.4  cv2.minMaxLoc()函數(shù)用法

  cv2.minMaxLoc() 函數(shù)功能:假設(shè)有一個矩陣 a,現(xiàn)在需要求這個矩陣的最小值,最大值,并得到最大值,最小值的索引。就可以使用此函數(shù)。

  cv2.minMaxLoc()函數(shù)源碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def minMaxLoc(src, mask=None): # real signature unknown; restored from __doc__
    """
    minMaxLoc(src[, mask]) -> minVal, maxVal, minLoc, maxLoc
    .   @brief Finds the global minimum and maximum in an array.
    .  
    .   The function cv::minMaxLoc finds the minimum and maximum element values and their positions. The
    .   extremums are searched across the whole array or, if mask is not an empty array, in the specified
    .   array region.
    .  
    .   The function do not work with multi-channel arrays. If you need to find minimum or maximum
    .   elements across all the channels, use Mat::reshape first to reinterpret the array as
    .   single-channel. Or you may extract the particular channel using either extractImageCOI , or
    .   mixChannels , or split .
    .   @param src input single-channel array.
    .   @param minVal pointer to the returned minimum value; NULL is used if not required.
    .   @param maxVal pointer to the returned maximum value; NULL is used if not required.
    .   @param minLoc pointer to the returned minimum location (in 2D case); NULL is used if not required.
    .   @param maxLoc pointer to the returned maximum location (in 2D case); NULL is used if not required.
    .   @param mask optional mask used to select a sub-array.
    .   @sa max, min, compare, inRange, extractImageCOI, mixChannels, split, Mat::reshape
    """
    pass

   函數(shù)返回值就是矩陣的最小值,最大值,最小值的索引,最大值的索引。

  下面舉個例子:

1
2
3
4
5
6
7
8
9
#_*_coding:utf-8_*_
import cv2
import numpy as np
a = np.array([[1,2,3,4], [5,6,7,8]])
min_val, max_val, min_index, max_index = cv2.minMaxLoc(a)
print(min_val, max_val, min_index, max_index)
# 1.0 8.0 (0, 0) (3, 1)

 

3.5 實戰(zhàn)——信用卡數(shù)字識別

  關(guān)于圖片和代碼,可以去我的GitHub中拿,GitHub地址在文章上面。

  這一實戰(zhàn)的目的是識別出信用卡中的數(shù)字,也就是我們的卡號,信用卡如下:

 

  而我們的模板圖片如下:

  對模板圖像處理過程:

  首先對圖像二值化,并對二值化的圖片進行逆運算:

  然后拿到原二值圖像的輪廓:

  最后將數(shù)字對應(yīng)的輪廓存入字典中,方便后面對比。

  對信用卡進行圖像處理,這里不再一一贅述,均在代碼中,只展示圖像的處理過程及其結(jié)果:

  灰度化信用卡圖像:

  對信用卡圖像進行頂帽處理:

   對圖像進行sobel算子的X方向:

   再進一步處理:

  對圖像進行膨脹腐蝕:

  再對圖像進行二值化:  進一步二值化:

  找到原圖的地址:

   設(shè)置篩選范圍,找到我們需要的區(qū)域:

  最后展示在原圖:

   也可以將結(jié)果展示在編譯器:

1
2
Credit Card Type: Visa
Credit Card #: 4000123456789010

   完整代碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
#_*_coding:utf-8_*_
import cv2
import numpy as np
# 指定信用卡類型
FIRST_NUMBER = {
    '3': "Amerian Express",
    '4': "Visa",
    '5': 'MasterCard',
    '6': 'Discover Card'
}
def cv_show(name, img):
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
def sort_contours(cnts, method='left-to-right'):
    reverse = False
    i = 0
    if method == 'right-to-left' or method == 'bottom-to-top':
        reverse = True
    if method == 'top-to-bottom' or method == ' bottom-to-top':
        i = 1
    # 用一個最小的矩形,把找到的形狀包起來 x, y, h, w
    boundingBoxes = [cv2.boundingRect(c) for c in cnts]
    # #zip(*)相當于解壓,是zip的逆過程
    (cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),
        key=lambda b: b[1][i], reverse=reverse))
    return cnts, boundingBoxes
def myresize(image, width=None, height=None, inter=cv2.INTER_AREA):
    dim = None
    (h, w) = image.shape[:2]
    if width is None and height is None:
        return image
    if width is None:
        r = height / float(h)
        dim = (int(w*r), height)
    else:
        r = width / float(w)
        dim = (width, int(h*r))
    resized = cv2.resize(image, dim, interpolation=inter)
    return resized
def trmplate_processing(template_image):
    # 讀取模板圖像
    template_img = cv2.imread(template_image)
    # cv_show('template_img', template_img)
    gray = cv2.cvtColor(template_img, cv2.COLOR_BGR2GRAY)
    # cv_show('gray', gray)
    # 二值圖像
    ref = cv2.threshold(gray, 10, 255, cv2.THRESH_BINARY_INV)[1]
    # cv_show('ref', ref)
    # 計算輪廓
    # cv2.findContours() 函數(shù)接受的參數(shù)為二值圖,即黑白的(不是灰度圖)
    # cv2.RETR_EXTERNAL 只檢測外輪廓  cv2.CHAIN_APPROX_SIMPLE 只保留終點坐標
    # 返回的list中每個元素都是圖像中的一個輪廓
    refCnts, hierarchy = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    drawimg = template_img.copy()
    cv2.drawContours(drawimg, refCnts, -1, (0, 0, 255), 3)
    # cv_show('drawimg', drawimg)
    # print(np.array(refCnts).shape)   # (10,)
    # 排序,從左到右,從上到下
    refCnts1 = sort_contours(refCnts, method='left-to-right')[0] 
    digits = {}
    # 遍歷每一個輪廓
    for (i, c) in enumerate(refCnts1):
        # 計算外接矩陣并且resize成合適大小
        (x, y, w, h) = cv2.boundingRect(c)
        roi = ref[y:y+h, x:x+w]
        roi = cv2.resize(roi, (57, 88))
        # 每一個數(shù)字對應(yīng)每個模板
        digits[i] = roi
    # print(digits)
    return digits
def origin_img_processing(origin_image, digits):
    # 讀入輸入圖像,并進行預(yù)處理
    img = cv2.imread(origin_image)
    # cv_show('img', img)
    # print(img.shape)  # (368, 583, 3)
    img = myresize(img, width=300)
    # print(img.shape)  # (189, 300, 3)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # cv_show('gray', gray)
    # 初始化卷積核
    rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3))
    sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
    # 禮帽操作,突出更明顯的區(qū)域
    tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel)
    # cv_show('tophat', tophat)
    # ksize = -1 相當于用 3*3 的 ksize=-1
    gradX = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=1, dy=0, ksize=-1)
    # 下面np函數(shù)等價于  cv2.convertScaleAbs(gradX)
    gradX = np.absolute(gradX)
    # cv_show('gradX', gradX)
    (minVal, maxVal) = (np.min(gradX), np.max(gradX))
    gradX = (255*((gradX - minVal) / (maxVal - minVal)))
    gradX = gradX.astype('uint8')
    # print(np.array(gradX).shape)  # (189, 300)
    # cv_show('gradX', gradX)
    # 通過閉操作(先膨脹,再腐蝕)將數(shù)字連在一起
    gradX = cv2.morphologyEx(gradX, cv2.MORPH_CLOSE, rectKernel)
    # cv_show('gradX', gradX)
    # THRESH_OTSU 會自動尋找合適的閾值,適合雙峰,需把閾值參數(shù)設(shè)置為0
    thresh = cv2.threshold(gradX, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
    # cv_show('thresh', thresh)
    # 再來一個閉操作  先膨脹后腐蝕
    thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, sqKernel)
    # cv_show('thresh_again', thresh)
    #計算輪廓
    threshCnts, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cur_img = img.copy()
    cv2.drawContours(cur_img, threshCnts, -1, (0, 0, 255), 3)
    # cv_show('cur_image', cur_img)
    locs = []
    # 遍歷輪廓
    for (i, c) in enumerate(threshCnts):
        # 計算矩形
        (x, y, w, h) = cv2.boundingRect(c)
        ar = w / float(h)
        # 選擇合適的區(qū)域,根據(jù)實際任務(wù)來,這里的基本都是四個數(shù)字一組
        if ar > 2.5 and ar<4.0:
            if (w > 40 and w < 55) and (h > 10 and h < 20):
                # 符合的留下來
                locs.append((x, y, w, h))
    # 將符合的輪廓從左到右排序
    locs = sorted(locs, key=lambda x:x[0])
    output = []
    # 遍歷輪廓中每一個數(shù)字
    for (i, (gX, gY, gW, gH)) in enumerate(locs):
        # initialize the list of group digits
        groupOutput = []
        # 根據(jù)坐標提取每一個組
        group = gray[gY - 5: gY + gH + 6, gX - 5:gX + gW + 5]
        # cv_show('group', group)
        # 預(yù)處理
        group1 = cv2.threshold(group, 0, 255, cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]
        # cv_show('group', group)
        # res = np.hstack((group, group1))
        # cv_show('group & threshold', res)
        # 計算每一組的輪廓
        digitCnts, hierarchy = cv2.findContours(group1.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        digitCnts = sort_contours(digitCnts, method='left-to-right')[0]
        # 計算每一組中的每一個數(shù)值
        for c in digitCnts:
            # 找到當前數(shù)值的輪廓,resize成合適的大小
            (x, y, w, h) = cv2.boundingRect(c)
            roi = group1[y:y+h, x:x+w]
            roi = cv2.resize(roi, (57, 88))
            # cv_show('roi', roi)
            # 計算匹配得分
            scores = []
            # 在模板中計算每一個得分
            for (digit, digitROI) in digits.items():
                # 模板匹配
                result = cv2.matchTemplate(roi, digitROI, cv2.TM_CCOEFF)
                (_, score, _, _) = cv2.minMaxLoc(result)
                scores.append(score)
            # 得到最合適的數(shù)字
            groupOutput.append(str(np.argmax(scores)))
        # 畫出來
        cv2.rectangle(img, (gX-5, gY-5), (gX+gW+5, gY+gH+5), (0, 0, 255), 1)
        cv2.putText(img, "".join(groupOutput), (gX, gY-15),
            cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)
        # 得到結(jié)果
        output.extend(groupOutput)
    # 打印結(jié)果
    print('Credit Card Type: {}'.format(FIRST_NUMBER[output[0]]))
    print("Credit Card #: {}".format("".join(output)))
    cv_show('Image', img)
if __name__ == '__main__':
    origin_image = r'images/credit_card_01.png'
    template_image = r'images/ocr_a_reference.png'
    digits = trmplate_processing(template_image)
    origin_img_processing(origin_image, digits)

 

  部分代碼解釋:

1
2
3
4
5
6
7
8
9
img = cv2.imread("card.png", 1)
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
template = cv2.imread("temp.png", 0)
w, h = template.shape[::-1]
res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
  
locs = np.where(res >=0.985)
for loc in zip(*locs[::-1]):
     img =cv2.rectangle(img, loc, (loc[0] + w, loc[1] + h), (0, 0, 255), 3)

   這里我跳出一些許多代碼,直接找到關(guān)鍵代碼:

  首先對于 locs = np.where(res > threshold) 進行分析,threshold 就是我們設(shè)定的閾值,res>thrshold 就是將結(jié)果array 里符合條件的數(shù)值換成True,反之換成 False。

  其次對于 np.where 的作用就是將 true的索引輸出到 Loc變量里面。

  loc[::-1] 將輸出的索引換成 x, y 坐標,因為索引和 x , y 坐標是正好相反的,所以要對換下位置。

 

四:關(guān)于OpenCV的安裝

  OpenCV的全稱open Sourse Computer Vision Library ,是一個跨平臺的計算機視覺庫,OpenCV可用于開發(fā)實時的圖像處理,計算機視覺以及模式識別的程序。

  OpenCV是用C++語言編寫,它的主要接口也是C++語言,但是依然保留了大量的C語言接口,該庫也有大量的Python,Java和MATLAB的接口,另外,一個使用CUDA的GPU接口也用于2010.9 開始實現(xiàn)。

3.1  為什么使用Python+OpenCV

  雖然python很強大,而且也有自己的圖像處理庫PIL,但是相對于OpenCV來講,它還是弱小很多。跟很多開源軟件一樣OpenCV也提供了完善的python接口,非常便于調(diào)用。OpenCV 的穩(wěn)定版是2.4.8,最新版是3.0,包含了超過2500個算法和函數(shù),幾乎任何一個能想到的成熟算法都可以通過調(diào)用OpenCV的函數(shù)來實現(xiàn),超級方便。

 

3.2  import cv2發(fā)生錯誤的解決方案

   錯誤如下:

  1,進入cmd控制臺,查看python版本

  2 根據(jù)自己用的python版本,下載對應(yīng)的OpenCV

https://www.lfd./~gohlke/pythonlibs/

 

   3,下載numpy,對應(yīng)的版本

https://pypi./pypi/numpy 

1
2
3
cp36代表著匹配python3.6版本。
win32、amd64代表著32位、64位系統(tǒng)。

  

  4,安裝OpenCV,下載下來是一個whl格式文件,把此文件放在安裝的文件名下,直接安裝。

 

  就這樣安裝成功。

 

  于2020.10.12 整理

參考文獻:https://blog.csdn.net/wsp_1138886114/article/details/81368890

公式地址如下:https://docs./3.3.1/df/dfb/group__imgproc__object.html#ga3a7850640f1fe1f58fe91a2d7583695d

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多