Обрезать (зашумленные) пробелы в изображениях с помощью Python - PullRequest
0 голосов
/ 04 ноября 2018

Скажите, что у меня есть изображение, как показано ниже:

enter image description here

Как вы можете видеть, изображение содержит пробел / пробел (с небольшими зелеными точками) в дополнение к большому зеленому квадрату (квадрат произвольно помещается в левый нижний угол). Что я хочу сделать, это обрезать изображение / обрезать пустое пространство, чтобы получить только большой зеленый квадрат в конце.
Благодаря сообществу Stackoverflow я нашел способ обрезать пустое пространство (если оно не содержит шум) в этом ответе ; вот код, который я использовал:

from PIL import Image, ImageChops

def trim(im):
    bg = Image.new(im.mode, im.size, im.getpixel((0,0)))
    diff = ImageChops.difference(im, bg)
    diff = ImageChops.add(diff, diff, 2.0, -100)
    diff.show()
    bbox = diff.getbbox()
    if bbox:
        return im.crop(bbox)

im = Image.open("noised.jpg")
im = trim(im)
im.save('output.png')

Поскольку пустое / пустое пространство содержит шум, полученное мной обрезанное изображение выглядит следующим образом:

enter image description here

Таким образом, сценарий обрезал изображение, когда оно встретилось с первым небелым (зашумленным) пикселем.
У меня такой вопрос: Есть ли способ подавить шум белого пространства без воздействия на изображение (зеленый квадрат) или напрямую обрезать белое пространство, даже если оно зашумлено?
Спасибо за вашу помощь!

Ответы [ 2 ]

0 голосов
/ 05 ноября 2018

Мое предложение - использовать библиотеки OpenCV и Numpy исключительно.

Предполагается, что ваше исходное изображение имеет имя «input_green.jpg». Метод основан на алгоритме обнаружения контура.

Прежде всего импортируйте и загрузите входное изображение и создайте соответствующий объект серого изображения.

import cv2
import numpy as np
img = cv2.imread("input_green.jpg", 1)
image_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)

Во-вторых, примените методы размытия изображения и бинаризации, а затем определите любые контуры.

image_gray = 255 - cv2.GaussianBlur(image_gray, (3,3), 0)
# clean the image based on gray value
image_gray = np.where(image_gray <= 50, 0, image_gray)
image_gray = np.where(image_gray > 50, 255, image_gray)
_,image_gray = cv2.threshold(image_gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# draw a bounding box around the whole image
h, w = image_gray.shape[:2]
cv2.rectangle(image_gray, (0,0), (w, h), 0, 5)

В-третьих, обнаружение и сортировка контуров по области

_,contours,_ = cv2.findContours(image_gray,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
contours_sorted = sorted(contours, key=cv2.contourArea, reverse=True)

Наконец, возьмите самый большой контур в виде зеленого прямоугольника на изображении и обрежьте его из исходного изображения.

green_rect = contours_sorted[0]
img_copy = img.copy()
cv2.drawContours(img_copy, [green_rect], 0, (0, 0, 255), 2)
cv2.imshow("result", img_copy)
#cv2.imwrite("result_green_rect.jpg", img_copy)
cv2.waitKey()

Временный результат: enter image description here

# crop the green rect
(x, y, w, h) = cv2.boundingRect(green_rect)
crop_result = img[y:y+h, x:x+w]
cv2.imshow("crop_result", crop_result)
#cv2.imwrite("result_green_rect_crop.jpg", crop_result)
cv2.waitKey()

Обрезанный результат:

enter image description here

0 голосов
/ 05 ноября 2018

Это можно сделать с помощью OpenCV, обнаружив зеленые области, а затем выбрав самую большую область. Существует несколько способов обнаружения зеленой зоны, включая cv2.inRange и cv2.threshold.

1. Выявление зеленых регионов

cv2.inRange

С помощью inRange вы можете идентифицировать цвета в определенном диапазоне. Например:

lower_bound = (0,100,0)
upper_bound = (10,255,10)

Таким образом, можно создать пиксели с цветами от lower_bound до upper_bound, чтобы создать маску с

mask = cv2.inRange(im, lower_bound, upper_bound)

Вот mask зеленых зон:

enter image description here

cv2.threshold

Точно так же, порог создаст маску зеленых зон. Сначала включите изображение в оттенки серого.

imgray = cv2.cvtColor(im, cv2.COLOR_RGB2GRAY)

enter image description here

Однако, если вы пороговое значение этого изображения, оно будет определять белые области, поэтому мы хотим, чтобы обратное пороговое значение было найдено в cv2.THRESH_BINARY_INV

ok, thresh = cv2.threshold(imgray, 200, 255, cv2.THRESH_BINARY_INV)

Вот пороговое изображение:

enter image description here

Как видно, thresh и mask идентифицируют зеленые области.

2. Контуры

Как только мы получим маску или пороговое изображение, мы можем определить белые области путем поиска контуров. Я буду использовать изображение mask (можно использовать и thresh).

(im2, contours, hierarchy)  = cv2.findContours(mask, cv2.RETR_EXTERNAL,
                                cv2.CHAIN_APPROX_SIMPLE)

Мы специально хотим contours, который дает набор точек, которые можно использовать для выделения зеленых областей. Нам нужен контур, который создает наибольшую площадь контура, которую мы можем найти, сначала расположив их по порядку от наибольшего к наименьшему, а затем выбрав первый.

ordered_cnts = sorted(contours, key=cv2.contourArea, reverse=True)
largest_cnt = ordered_cnts[0]

largest_cnt - следующий набор точек:

[[[  0 701]]
 [[  0 999]]
 [[298 999]]
 [[298 701]]
 [[289 701]]
 [[288 702]]
 [[287 701]]]

Эти точки можно использовать для выделения зеленого поля в левом нижнем углу изображения. Нам нужен только один прямоугольник, чтобы мы могли очертить весь контур, найдя наименьший прямоугольник, который будет окружать все эти точки.

rect = cv2.minAreaRect(largest_cnt)
box = cv2.boxPoints(rect)

box дает список точек, которые являются четырьмя углами rect. Мы можем использовать numpy для преобразования в целочисленные точки и получить пределы поля для обрезки изображения.

box = np.array(box, dtype=int)
x0, y0 = np.min(box,axis=0)
x1, y1 = np.max(box,axis=0)
crop = im[y0:y1, x0:x1]

Изображение crop:

enter image description here

Комбинированный код

lower_bound = (0,100,0)
upper_bound = (10,255,10)
mask = cv2.inRange(im, lower_bound, upper_bound)
(im2, cnts, hierarchy) = cv2.findContours(mask, cv2.RETR_EXTERNAL,
                                    cv2.CHAIN_APPROX_SIMPLE)
ordered_cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
largest_cnt = ordered_cnts[0]
rect = cv2.minAreaRect(largest_cnt)
box = cv2.boxPoints(rect)
box = np.array(box, dtype=int)
x0, y0 = np.min(box,axis=0)
x1, y1 = np.max(box,axis=0)
crop = im[y0:y1, x0:x1]
...