项目

一般

简介

MatchTemplate.py

匿名用户, 2023-08-26 17:36

 
1
import argparse
2
import os
3
import cv2
4
import numpy as np
5
import time
6

    
7
def ImageRotate(img, angle):   # img:输入图片;newIm:输出图片;angle:旋转角度(°)
8
    height, width = img.shape[:2]  # 输入(H,W,C),取 H,W 的值
9
    center = (width // 2, height // 2)  # 绕图片中心进行旋转
10
    M = cv2.getRotationMatrix2D(center, angle, 1.0)
11
    image_rotation = cv2.warpAffine(img, M, (width, height))
12
    return image_rotation
13

    
14
def circle_tr(src):
15
    dst = np.zeros(src.shape, np.uint8)  # 感兴趣区域ROI
16
    mask = np.zeros(src.shape, dtype='uint8')  # 感兴趣区域ROI
17
    (h, w) = mask.shape[:2]
18
    (cX, cY) = (w // 2, h // 2)  # 是向下取整
19
    radius = int(min(h, w) / 2)
20
    cv2.circle(mask, (cX, cY), radius, (255, 255, 255), -1)
21
    # 以下是copyTo的算法原理:
22
    # 先遍历每行每列(如果不是灰度图还需遍历通道,可以事先把mask图转为灰度图)
23
    for row in range(mask.shape[0]):
24
        for col in range(mask.shape[1]):
25
            # 如果掩图的像素不等于0,则dst(x,y) = scr(x,y)
26
            if mask[row, col] != 0:
27
                # dst_image和scr_Image一定要高宽通道数都相同,否则会报错
28
                dst[row, col] = src[row, col]
29
                # 如果掩图的像素等于0,则dst(x,y) = 0
30
            elif mask[row, col] == 0:
31
                dst[row, col] = 0
32
    return dst
33

    
34
def ImagePyrDown(image,NumLevels):
35
    for i in range(NumLevels):
36
        image = cv2.pyrDown(image)       #pyrDown下采样
37
    return image
38

    
39

    
40
# 旋转匹配函数(输入参数分别为模板图像、待匹配图像)
41
def RatationMatch(modelpicture, searchpicture, Layer):
42
    searchtmp = []
43
    modeltmp = []
44

    
45
    searchtmp = ImagePyrDown(searchpicture, Layer)
46
    modeltmp = ImagePyrDown(modelpicture, Layer)
47

    
48
    newIm = circle_tr(modeltmp)
49
    # 使用matchTemplate对原始灰度图像和图像模板进行匹配
50
    res = cv2.matchTemplate(searchtmp, newIm, cv2.TM_SQDIFF_NORMED)
51
    min_val, max_val, min_indx, max_indx = cv2.minMaxLoc(res)
52
    location = min_indx
53
    temp = min_val
54
    angle = 0  # 当前旋转角度记录为0
55

    
56
    # 以步长为5进行第一次粗循环匹配
57
    for i in range(-180, 181, 5):
58
        newIm= ImageRotate(modeltmp, i)
59
        newIm = circle_tr(newIm)
60
        res = cv2.matchTemplate(searchtmp, newIm, cv2.TM_SQDIFF_NORMED)
61
        min_val, max_val, min_indx, max_indx = cv2.minMaxLoc(res)
62
        if min_val < temp:
63
            location = min_indx
64
            temp = min_val
65
            angle = i
66

    
67
    # 在当前最优匹配角度周围10的区间以1为步长循环进行循环匹配计算
68
    for j in range(angle - 5, angle + 6):
69
        newIm = ImageRotate(modeltmp, j)
70
        newIm = circle_tr(newIm)
71
        res = cv2.matchTemplate(searchtmp, newIm, cv2.TM_SQDIFF_NORMED)
72
        min_val, max_val, min_indx, max_indx = cv2.minMaxLoc(res)
73
        if min_val < temp:
74
            location = min_indx
75
            temp = min_val
76
            angle = j
77

    
78
    # 在当前最优匹配角度周围2的区间以0.1为步长进行循环匹配计算
79
    k_angle = angle - 0.9
80
    for k in range(0, 19):
81
        k_angle = k_angle + 0.1
82
        newIm = ImageRotate(modeltmp, k_angle)
83
        newIm = circle_tr(newIm)
84
        res = cv2.matchTemplate(searchtmp, newIm, cv2.TM_SQDIFF_NORMED)
85
        min_val, max_val, min_indx, max_indx = cv2.minMaxLoc(res)
86
        if min_val < temp:
87
            location = min_indx
88
            temp = min_val
89
            angle = k_angle
90

    
91
    # 用下采样前的图片来进行精匹配计算
92
    k_angle = angle - 0.1
93
    newIm = ImageRotate(modelpicture, k_angle)
94
    newIm = circle_tr(newIm)
95
    res = cv2.matchTemplate(searchpicture, newIm, cv2.TM_CCOEFF_NORMED)
96
    min_val, max_val, min_indx, max_indx = cv2.minMaxLoc(res)
97
    location = max_indx
98
    temp = max_val
99
    angle = k_angle
100

    
101

    
102
    for k in range(1, 3):
103
        k_angle = k_angle + 0.1
104
        newIm= ImageRotate(modelpicture, k_angle)
105
        newIm = circle_tr(newIm)
106
        res = cv2.matchTemplate(searchpicture, newIm, cv2.TM_CCOEFF_NORMED)
107
        min_val, max_val, min_indx, max_indx = cv2.minMaxLoc(res)
108
        if max_val > temp:
109
            location = max_indx
110
            temp = max_val
111
            angle = k_angle
112

    
113
    location_x = location[0] #+ 50
114
    location_y = location[1] #+ 50
115

    
116
    # 前面得到的旋转角度是匹配时模板图像旋转的角度,后面需要的角度值是待检测图像应该旋转的角度值,故需要做相反数变换
117
    angle = -angle
118

    
119
    match_point = {'angle': angle, 'point': (location_x, location_y)}
120
    return match_point
121

    
122
# 画图
123
def draw_result(src, temp, match_pointp, match_pointa):
124
    height, width = temp.shape[:2]  # 输入(H,W,C),取 H,W 的值
125
    size = (height,width)
126
    center = (match_pointp[0]+width/2, match_pointp[1]+height/2)  # 绕图片中心进行旋转
127
    M = cv2.getRotationMatrix2D(center, -match_pointa, 1.0)
128
    rect_points = cv2.boxPoints(((center[0], center[1]), size, 0))
129
    rect_points = np.int0(cv2.transform(np.array([rect_points]), M))[0]
130

    
131
    cv2.polylines(src, [rect_points], isClosed=True, color=(0, 255, 0), thickness=2)
132

    
133
    #cv2.rectangle(src, match_pointp,
134
                  #(match_pointp[0] + temp.shape[1], match_pointp[1] + temp.shape[0]),
135
                  #(0, 255, 0), 2)
136
    #cv2.imshow('result', src)
137
    #cv2.waitKey()
138
    print("坐标",center)
139

    
140
def oimage_read_from_chinese_path(ppath, TemplatePath, Layer):
141
    img = cv2.imdecode(np.fromfile(ppath,
142
                                   dtype=np.uint8), 1)
143
    templeimg = cv2.imdecode(np.fromfile(TemplatePath,
144
                                         dtype=np.uint8), 1)
145
    ModelImage = templeimg
146
    SearchImage = img
147
    ModelImage_edge = cv2.GaussianBlur(ModelImage, (5, 5), 0)
148
    ModelImage_edge = cv2.Canny(ModelImage_edge, 10, 200, apertureSize=3)
149
    SearchImage_edge = cv2.GaussianBlur(SearchImage, (5, 5), 0)
150

    
151
    (h1, w1) = SearchImage_edge.shape[:2]
152
    SearchImage_edge = cv2.Canny(SearchImage_edge, 10, 180, apertureSize=3)
153
    serch_ROIPart = SearchImage_edge[50:h1 - 50, 50:w1 - 50]  # 裁剪图像
154

    
155
    match_points = RatationMatch(ModelImage_edge, SearchImage_edge, Layer)
156

    
157
    #TmpImage_edge = ImageRotate(SearchImage_edge, match_points['angle'])
158
    #cv2.imshow("TmpImage_edge", TmpImage_edge)
159
    #cv2.waitKey()
160
    draw_result(SearchImage, ModelImage_edge, match_points['point'], match_points['angle'])
161

    
162
    print("角度", -match_points['angle'])
163

    
164
    return SearchImage
165

    
166

    
167
def print_hi(imgpath, Process, Xstart, Ystart, Xend, Yend, Layer):
168

    
169
    if Process == 1:
170

    
171
        TemplatePath = "croppedimage.bmp"
172

    
173
        img_path = oimage_read_from_chinese_path(imgpath, TemplatePath, Layer)
174

    
175
        cv2.imwrite("OutImage.bmp", img_path)
176
    elif Process == 0:
177

    
178
        image_numpy_data = cv2.imdecode(np.fromfile(imgpath, dtype=np.uint8), 1)
179
        #image_numpy_data = cv2.imread(imgpath)
180

    
181
        cropped_image = image_numpy_data[Ystart:Yend, Xstart:Xend]
182
        cv2.rectangle(image_numpy_data, (Xstart,Ystart),
183
                      (Xend, Yend),
184
                      (0, 255, 0), 2)
185

    
186
        cv2.imwrite("croppedimage.bmp", cropped_image)
187
        cv2.imwrite("OutImage.bmp", image_numpy_data)
188

    
189
# Press the green button in the gutter to run the script.
190

    
191

    
192
if __name__ == '__main__':
193
    parser = argparse.ArgumentParser()
194
    parser.add_argument("--ImagePath", type=str, required=True)
195
    parser.add_argument("--Process", type=int, required=True)
196
    parser.add_argument("--Xstart", type=int, required=True)
197
    parser.add_argument("--Ystart", type=int, required=True)
198
    parser.add_argument("--Xend", type=int, required=True)
199
    parser.add_argument("--Yend", type=int, required=True)
200
    parser.add_argument("--Layer", type=int, required=True)
201
    args = parser.parse_args()
202
    print_hi(args.ImagePath, args.Process, args.Xstart, args.Ystart, args.Xend, args.Yend,  args.Layer)