создание кругов в python для маскировки изображения и подсчета пикселей в каждом круге

1

В python я пытаюсь разделить изображение на круги и вычислять количество черных пикселей в каждом круге.

Например, у меня есть изображение, снятое линзой с рыбий глаз (полусферическое изображение) (на примере ниже), и я хочу разделить изображение на маленькие круги, захватывая часть изображения с небольшого круга посередине на весь образ, Изображение 174551

Я хотел бы разбить изображение на х количество кругов, каждый раз захватывая часть изображения (см. Изображения ниже) Изображение 174551 Изображение 174551

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

Я попытался: Image=Image.new("RGB", (2000,2000)) draw = ImageDraw.Draw(image) draw.ellipse((20,20,1800,1800),fill(255,255,255)

Затем создала маску из этого, но независимо от того, как я изменяю числа int draw.ellipse, круг только когда-либо захватывает все изображение, но делает изображение меньше.

Любые идеи или рекомендации о том, как исправить это, будут действительно оценены!

Теги:
image-processing
image

2 ответа

2
Лучший ответ

Вы должны посмотреть на OpenCV для таких задач. Вы можете преобразовать круг в весь контур и вычислить радиус круга. Затем вы можете нарисовать круг и нарисовать их на маске и выполнить cv2.bitwise_and чтобы сделать ROI круга над изображением. Вы можете повторять и умножать целое число по вашему выбору (в моем случае 10) радиус круга ROI. Надеюсь, поможет. Ура!

Пример кода:

import cv2
import numpy as np

img = cv2.imread('circle.png')
h, w = img.shape[:2]
mask = np.zeros((h, w), np.uint8)

gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
kernel = np.ones((10,10),np.uint8)
opening = cv2.morphologyEx(thresh,cv2.MORPH_CLOSE,kernel, iterations = 2)
_, contours, hierarchy = cv2.findContours(opening,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt = max(contours, key=cv2.contourArea)
extLeft = tuple(cnt[cnt[:, :, 0].argmin()][0])
extRight = tuple(cnt[cnt[:, :, 0].argmax()][0])
radius = (extRight[0] - extLeft[0])/2
print(extRight[0], extLeft[0])
print(radius)

M = cv2.moments(cnt)
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
print(cx, cy)

for i in range(1,30):
    if i*10<radius:
        print(i*10)
        cv2.circle(mask,(cx,cy), i*10, 255, -1)
        res = cv2.bitwise_and(img, img, mask=mask)
        pixels = np.sum(res == 255)
        cv2.putText(res,'Pixel count: '+str(pixels),(30,30), cv2.FONT_HERSHEY_COMPLEX, 0.5, (255,255,255), 1, cv2.LINE_AA)
        cv2.imshow('img', res)
        cv2.waitKey(0)
        cv2.destroyAllWindows()
    else:
        res = cv2.bitwise_and(img, img, mask=opening)
        pixels = np.sum(res == 255)
        cv2.putText(img,'Pixel count: '+str(pixels),(30,30), cv2.FONT_HERSHEY_COMPLEX, 0.5, (255,255,255), 1, cv2.LINE_AA)
        cv2.imshow('img', res)
        cv2.waitKey(0)
        cv2.destroyAllWindows()
        break

Результат:

Изображение 174551

Изображение 174551

Изображение 174551

РЕДАКТИРОВАТЬ:

Попробуйте другой способ рассчитать средний

import cv2
import numpy as np

img = cv2.imread('circle.png')
h, w = img.shape[:2]
mask = np.zeros((h, w), np.uint8)

gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
kernel = np.ones((10,10),np.uint8)
opening = cv2.morphologyEx(thresh,cv2.MORPH_CLOSE,kernel, iterations = 2)
_, contours, hierarchy = cv2.findContours(opening,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt = max(contours, key=cv2.contourArea)
cv2.imshow('img22', opening)
extLeft = tuple(cnt[cnt[:, :, 0].argmin()][0])
extRight = tuple(cnt[cnt[:, :, 0].argmax()][0])
radius = (extRight[0] - extLeft[0])/2

x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)

cx = int(x+(w/2))
cy = int(y+h/2)

for i in range(1,30):
    if i*10<radius:
        print(i*10)
        cv2.circle(mask,(cx,cy), i*10, 255, -1)
        res = cv2.bitwise_and(img, img, mask=mask)
        pixels = np.sum(res == 255)
        cv2.putText(res,'Pixel count: '+str(pixels),(30,30), cv2.FONT_HERSHEY_COMPLEX, 0.5, (255,255,255), 1, cv2.LINE_AA)
        cv2.imshow('img', res)
        cv2.waitKey(0)
        cv2.destroyAllWindows()
    else:
        res = cv2.bitwise_and(img, img, mask=opening)
        pixels = np.sum(res == 255)
        cv2.putText(img,'Pixel count: '+str(pixels),(30,30), cv2.FONT_HERSHEY_COMPLEX, 0.5, (255,255,255), 1, cv2.LINE_AA)
        cv2.imshow('img', res)
        cv2.waitKey(0)
        cv2.destroyAllWindows()
        break

Изменить 2:

Хорошо, поэтому мое предположение из вашего первого примера изображения состояло в том, что ваш образ будет почти кругом от начала. Потому что вам не нужно вычислять центр по-разному (например, из моего первого редактирования - из ограничивающей рамки) и создавать большее ядро (40,40) - из-за того, что изображение очень велико. Кроме того, вы должны сделать для я в диапазоне порога (например, 10000). Это будет работать:

import cv2
import numpy as np

img = cv2.imread('circleroi.jpg')
h, w = img.shape[:2]
mask = np.zeros((h, w), np.uint8)

gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
kernel = np.ones((40,40),np.uint8)
opening = cv2.morphologyEx(thresh,cv2.MORPH_CLOSE,kernel, iterations = 2)

_, contours, hierarchy = cv2.findContours(opening,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt = max(contours, key=cv2.contourArea)
extLeft = tuple(cnt[cnt[:, :, 0].argmin()][0])
extRight = tuple(cnt[cnt[:, :, 0].argmax()][0])
radius = (extRight[0] - extLeft[0])/2

x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)

cx = int(x+(w/2))
cy = int(y+h/2)

for i in range(1,10000):
    if i*10<radius:
        cv2.circle(mask,(cx,cy), i*10, 255, -1)
        res = cv2.bitwise_and(img, img, mask=mask)
        pixels = np.sum(res == 255)
        cv2.putText(res,'Pixel count: '+str(pixels),(30,30), cv2.FONT_HERSHEY_COMPLEX, 0.5, (255,255,255), 1, cv2.LINE_AA)
        cv2.imshow('img', res)
        cv2.waitKey(0)
        cv2.destroyAllWindows()
    else:
        res = cv2.bitwise_and(img, img, mask=opening)
        pixels = np.sum(res == 255)
        cv2.putText(img,'Pixel count: '+str(pixels),(30,30), cv2.FONT_HERSHEY_COMPLEX, 0.5, (255,255,255), 1, cv2.LINE_AA)
        cv2.imshow('img', res)
        cv2.waitKey(0)
        cv2.destroyAllWindows()
        break
  • 0
    Спасибо за код, он выглядит великолепно, и я попробовал это, но, к сожалению, изображение действительно большое, и круг не появляется в середине экрана. Есть ли причина для этого?
  • 0
    Вы можете опубликовать эту картинку? Попытайтесь сделать ядро большего размера для открытия (20, 20 или 30, 30) - возможно, он не сделает один контур, если размер ядра слишком мал, следовательно, другая средняя точка
Показать ещё 6 комментариев
1

Это довольно просто сделать в чистом numpy, если вы достаточно знакомы с библиотекой:

# Create some fake data
np.random.seed(100)
fake_im_arr = np.random.randint(low=0, high=2, size=(2000,2000))

# Function definition for creating masks
def create_circle_mask(X_arr, Y_arr, center, radius):
    c_x, c_y = center
    dists_sqrd = (X_arr - c_x)**2 + (Y_arr - c_y)**2
    return dists_sqrd <= radius**2

# Using the two together:
center, radius = (1000, 1000), 5
size_x, size_y = fake_im_arr.shape
mask = create_circle_mask(*np.ogrid[0:size_x, 0:size_y], center=center, radius=radius)
n_black_in_circle = ((fake_im_arr == 1) & mask).sum() # This is your answer (39 in this case)

Чтобы увидеть, как выглядят различные массивы:

fake_im_arr[center[0] - radius:center[0] + (radius + 1),
            center[1] - radius:center[1] + (radius + 1)]

array([[0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1],
       [0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1],
       [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1],
       [0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1],
       [1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1],
       [1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0],
       [0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1],
       [1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0],
       [0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0],
       [1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0]])

mask[center[0] - radius:center[0] + (radius + 1),
     center[1] - radius:center[1] + (radius + 1)].astype('int')

array([[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
       [0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0],
       [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
       [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
       [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
       [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
       [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
       [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
       [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
       [0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0],
       [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]])

np.where(mask, fake_im_arr, 0)[center[0] - radius:center[0] + (radius + 1),
                               center[1] - radius:center[1] + (radius + 1)]

array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0],
       [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0],
       [0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0],
       [1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1],
       [0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0],
       [0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0],
       [0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0],
       [0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0],
       [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]])

Ещё вопросы

Сообщество Overcoder
Наверх
Меню