Какой самый простой способ вырезать миниатюру круга из изображения? - PullRequest
3 голосов
/ 24 октября 2019

Я пытаюсь обрезать центрированный (или не центрированный) круг из этого изображения:

enter image description here

Я украл этот код из существующих вопросов, касающихсяВ этом разделе о переполнении стека что-то идет не так:

import cv2

file = 'dog.png'

img = cv2.imread(file)
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
circle = cv2.HoughCircles(img,
                          3,
                          dp=1.5,
                          minDist=10,
                          minRadius=1,
                          maxRadius=10)
x = circle[0][0][0]
y = circle[0][0][1]
r = circle[0][0][2]

rectX = (x - r) 
rectY = (y - r)
crop_img = img[rectY:(rectY+2*r), rectX:(rectX+2*r)]
cv2.imwrite('dog_circle.png', crop_img)

Вывод:

Traceback (most recent call last):
  File "C:\Users\Artur\Desktop\crop_circle - Kopie\crop_circle.py", line 14, in <module>
    x = circle[0][0][0]
TypeError: 'NoneType' object is not subscriptable

cv2.HoughCircles(), кажется, выдает None вместо обрезанного массива окружностей. Как мне это исправить?

Ответы [ 3 ]

3 голосов
/ 24 октября 2019

first: HoughCircles используется для обнаружения кругов на изображении, а не для его обрезки.


Вы не можете иметь изображение круга. Изображение всегда прямоугольное, но некоторые пиксели могут быть прозрачными (альфа-канал в RGBA), и программы не будут отображать их.

Таким образом, вы можете сначала обрезать изображение, чтобы получить квадрат, а затем добавить альфа-канал с информацией о том, какие пиксели должны быть видны. И здесь вы можете использовать маску с белым кружком на черном фоне. В конце вы должны сохранить его как png или tiff, потому что jpg не может поддерживать альфа-канал.


Я использую модуль PIL / pillow для этого.

Я обрезаю квадратную область в центре изображения, но вы можете использовать для этого разные координаты.

Далее я создаю изображение в градациях серого с тем же размером и черным фоном и рисую белый круг / эллипс.

Наконец, я добавляю это изображение как альфа-канал к кадрированному изображению и сохраняю его как png.

from PIL import Image, ImageDraw

filename = 'dog.jpg'

# load image
img = Image.open(filename)

# crop image 
width, height = img.size
x = (width - height)//2
img_cropped = img.crop((x, 0, x+height, height))

# create grayscale image with white circle (255) on black background (0)
mask = Image.new('L', img_cropped.size)
mask_draw = ImageDraw.Draw(mask)
width, height = img_cropped.size
mask_draw.ellipse((0, 0, width, height), fill=255)
#mask.show()

# add mask as alpha channel
img_cropped.putalpha(mask)

# save as png which keeps alpha channel 
img_cropped.save('dog_circle.png')

img_cropped.show()

Результат

enter image description here


Кстати:

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

Если вы хотите использовать его в HTML на своей странице, вам не нужно создавать круговое изображение, потому что веб-браузер может закруглять углы изображения и отображать его в виде круга. Вы должны использовать CSS для этого.


РЕДАКТИРОВАТЬ: Пример с большим количеством кругов на маске.

enter image description here

from PIL import Image, ImageDraw

filename = 'dog.jpg'

# load image
img = Image.open(filename)

# crop image 
width, height = img.size
x = (width - height)//2
img_cropped = img.crop((x, 0, x+height, height))

# create grayscale image with white circle (255) on black background (0)
mask = Image.new('L', img_cropped.size)
mask_draw = ImageDraw.Draw(mask)
width, height = img_cropped.size
mask_draw.ellipse((50, 50, width-50, height-50), fill=255)
mask_draw.ellipse((0, 0, 250, 250), fill=255)
mask_draw.ellipse((width-250, 0, width, 250), fill=255)

# add mask as alpha channel
img_cropped.putalpha(mask)

# save as png which keeps alpha channel 
img_cropped.save('dog_2.png')

img_cropped.show()
1 голос
/ 24 октября 2019

Этот ответ объясняет, как применять маску. Сначала прочитайте на изображении:

import cv2
import numpy as np
img = cv2.imread('dog.jpg')

Затем создайте маску или пустое изображение того же размера, что и исходное изображение:

h,w,_ = img.shape
mask = np.zeros((h,w), np.uint8)

Затем нарисуйте круг намаска. Измените эти параметры в зависимости от того, где находится лицо:

cv2.circle(mask, (678,321), 5, 255, 654)

Наконец, замаскируйте исходное изображение:

img = cv2.bitwise_and(img, img, mask= mask)

Вот маска:

mask

А на выходе:

output

0 голосов
/ 25 октября 2019

Идея состоит в том, чтобы создать черную маску, а затем нарисовать желаемую область для обрезки белым цветом, используя cv2.circle(). Оттуда мы можем использовать cv2.bitwise_and() с исходным изображением и маской. Чтобы обрезать результат, мы можем использовать cv2.boundingRect() на маске для получения ROI, а затем использовать Numpy нарезку для извлечения результата. Для этого примера я использовал центральную точку, полученную из ширины и высоты изображения

image

import cv2
import numpy as np

# Create mask and draw circle onto mask
image = cv2.imread('1.jpg')
mask = np.zeros(image.shape, dtype=np.uint8)
x,y = image.shape[1], image.shape[0]
cv2.circle(mask, (x//2,y//2), 300, (255,255,255), -1)

# Bitwise-and for ROI
ROI = cv2.bitwise_and(image, mask)

# Crop mask and turn background white
mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
x,y,w,h = cv2.boundingRect(mask)
result = ROI[y:y+h,x:x+w]
mask = mask[y:y+h,x:x+w]
result[mask==0] = (255,255,255)

cv2.imshow('result', result)
cv2.waitKey()
...