Итак, я попробовал два разных метода:
Обнаружение контура - Это, казалось, самый очевидный метод, поскольку экран статистики является основным часть изображения и присутствует во всех ваших изображениях.Хотя он работает с двумя из трех изображений, он может быть не очень надежным с параметрами.Вот шаги, которые я попробовал для контура:
Сначала получите изображение в оттенках серого или выберите один из каналов Значение в HSV .Затем пороговое значение изображения с помощью Otsu или Adaptive Thresholding .После игры с большим количеством связанных параметров я получил удовлетворительные результаты, которые в основном означали бы хороший целый экран статистики белого цвета на черном фоне.После этого сортируйте контуры следующим образом:
contours = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[1]
# Sort the contours to avoid unnecessary comparison in the for loop below
cntsSorted = sorted(contours, key=lambda x: cv2.contourArea(x), reverse=True)
for cnt in cntsSorted[0:20]:
peri = cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, 0.04 * peri, True)
if len(approx) == 4 and peri > 10000:
cv2.drawContours(sorted_image, cnt, -1, (0, 255, 0), 10)
Обнаружение и сопоставление элементов: поскольку использование контуров было недостаточно надежным, я попробовал другой метод, над которым работалпохожая проблема, как у вас.Этот метод довольно надежный, намного быстрее (я пробовал это на телефоне Android 2 года назад, и он сделал бы работу менее чем за секунду для изображения 1280 x 760).Однако, после примерки ваших рабочих кейсов, я понял, что ваши изображения довольно расплывчаты.Я имею в виду, что у вас есть два изображения в вашем вопросе, которые имеют довольно похожих праймериз , и это работает для этого, но изображения, которые вы разместили в комментариях, очень отличаются от этих и, следовательно,он не находит подходящего количества хороших совпадений (по крайней мере, 10 в моем случае).Если вы можете опубликовать хороший набор изображений, с которыми вы на самом деле столкнетесь, я обновлю этот ответ моими результатами в новом наборе.Что еще более важно, изображения сцены, очевидно, меняются в перспективе, что не должно вызывать проблем, если вы способны получить очень хорошее исходное изображение (как первое в вашем вопросе).Однако изменение условий освещения может быть болезненным.Я бы предложил использовать другие цветовые пространства, такие как HSV, Lab и Luv вместо BGR. Здесь , где вы можете найти рабочий пример того, как реализовать свой собственный сопоставитель функций.Существуют некоторые изменения кода, необходимые в зависимости от используемой версии OpenCV, но я уверен, что вы сможете найти решения (я сделал;)).
Хороший пример:
Некоторые предложения:
Попробуйте получитьмаксимально чистое изображение для изображения, которое вы используете, чтобы соответствовать другим (ваше первое изображение в моем случае).Надеюсь, это потребует от вас меньше обработки.
Попробуйте использовать нерезкую маску перед нахождением ключевых точек.
Мои результаты получены при использовании ORB ,Вы также можете попробовать другие детекторы / дескрипторы, такие как SURF, SIFT и FAST.
Наконец, ваш подход к сопоставлению шаблонов должен работать в тех случаях, когда есть изменение только в масштабировании, а неперспектива.
Надеюсь, это поможет!Напишите комментарий, если у вас есть какие-либо дополнительные вопросы и / или когда у вас есть готовая хорошая картинка (потирает ладони).Ура!
Редактировать 1: это код, который я использовал для обнаружения и сопоставления функций в Opencv 3.4.3 и Python 3.4
def unsharp_mask(im):
# This is used to sharpen images
gaussian_3 = cv2.GaussianBlur(im, (3, 3), 3.0)
return cv2.addWeighted(im, 2.0, gaussian_3, -1.0, 0, im)
def screen_finder2(image, source, num=0):
def resize(im, new_width):
r = float(new_width) / im.shape[1]
dim = (new_width, int(im.shape[0] * r))
return cv2.resize(im, dim, interpolation=cv2.INTER_AREA)
width = 300
source = resize(source, new_width=width)
image = resize(image, new_width=width)
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2LUV)
image, u, v = cv2.split(hsv)
hsv = cv2.cvtColor(source, cv2.COLOR_BGR2LUV)
source, u, v = cv2.split(hsv)
MIN_MATCH_COUNT = 10
orb = cv2.ORB_create()
kp1, des1 = orb.detectAndCompute(image, None)
kp2, des2 = orb.detectAndCompute(source, None)
flann = cv2.DescriptorMatcher_create(cv2.DescriptorMatcher_FLANNBASED)
# Without the below 2 lines, matching doesn't work
des1 = np.asarray(des1, dtype=np.float32)
des2 = np.asarray(des2, dtype=np.float32)
matches = flann.knnMatch(des1, des2, k=2)
# store all the good matches as per Lowe's ratio test
good = []
for m, n in matches:
if m.distance < 0.7 * n.distance:
good.append(m)
if len(good) >= MIN_MATCH_COUNT:
src_pts = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1,
1, 2)
dst_pts = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1,
1, 2)
M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
matchesMask = mask.ravel().tolist()
h,w = image.shape
pts = np.float32([[0, 0], [0, h-1], [w-1, h-1], [w-1, 0]]).reshape(-1,
1, 2)
dst = cv2.perspectiveTransform(pts, M)
source_bgr = cv2.cvtColor(source, cv2.COLOR_GRAY2BGR)
img2 = cv2.polylines(source_bgr, [np.int32(dst)], True, (0,0,255), 3,
cv2.LINE_AA)
cv2.imwrite("out"+str(num)+".jpg", img2)
else:
print("Not enough matches." + str(len(good)))
matchesMask = None
draw_params = dict(matchColor=(0, 255, 0), # draw matches in green color
singlePointColor=None,
matchesMask=matchesMask, # draw only inliers
flags=2)
img3 = cv2.drawMatches(image, kp1, source, kp2, good, None, **draw_params)
cv2.imwrite("ORB"+str(num)+".jpg", img3)
match_image = unsharp_mask(cv2.imread("source.jpg"))
image_1 = unsharp_mask(cv2.imread("Screen_1.jpg"))
screen_finder2(match_image, image_1, num=1)