Невозможно увеличить область интереса изображения - PullRequest
0 голосов
/ 23 октября 2019

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

Сначала определяется набор пикселей внешней границы области интереса, т. Е. Пикселей, которыенаходятся за пределами области интереса и являются соседями (используя четыре окрестности) для пикселей внутри него. Затем каждое значение пикселя этого набора заменяется средним значением его соседей (на этот раз с использованием восьми соседей) внутри области интереса. Наконец, ROI расширяется путем включения этого измененного набора пикселей. Этот процесс повторяется и может рассматриваться как искусственное увеличение ROI.

enter image description here

Псевдокод ниже -

while there are border pixels:
    border_pixels = []

    # find the border pixels
    for each pixel p=(i, j) in image
        if p is not in ROI and ((i+1, j) in ROI or (i-1, j) in ROI or (i, j+1) in ROI or (i, j-1) in ROI) or (i-1,j-1) in ROI or (i+1,j+1) in ROI):
            add p to border_pixels

    # calculate the averages
    for each pixel p in border_pixels:
        color_sum = 0
        count = 0
        for each pixel n in 8-neighborhood of p:
            if n in ROI:
                color_sum += color(n)
                count += 1
        color(p) = color_sum / count

    # update the ROI
    for each pixel p=(i, j) in border_pixels:
        set p to be in ROI


Ниже приведен мой код

    img = io.imread(path_dir)
    newimg = np.zeros((584, 565,3))
    mask = img == 0
    while(1):
        border_pixels = []
        for i in range(img.shape[0]):
            for j in range(img.shape[1]):
               for k in range(0,3):
                if(i+1<=583 and j+1<=564 and i-1>=0 and j-1>=0):
                    if ((mask[i][j][k]) and ((mask[i+1][j][k]== False) or (mask[i-1][j][k]==False) or (mask[i][j+1][k]==False) or (mask[i][j-1][k]==False) or (mask[i-1][j-1][k] == False) or(mask[i+1][j+1][k]==False))):
                        border_pixels.append([i,j,k])

         if len(border_pixels) == 0:
             break

        for (each_i,each_j,each_k) in border_pixels:
            color_sum = 0
            count = 0
            eight_neighbourhood = [[each_i-1,each_j],[each_i+1,each_j],[each_i,each_j-1],[each_i,each_j+1],[each_i-1,each_j-1],[each_i-1,each_j+1],[each_i+1,each_j-1],[each_i+1,each_j+1]]
            for pix_i,pix_j in eight_neighbourhood:
                if (mask[pix_i][pix_j][each_k] == False):
                    color_sum+=img[pix_i,pix_j,each_k]
                    count+=1
            print(color_sum//count)
            img[each_i][each_j][each_k]=(color_sum//count)

        for (i,j,k) in border_pixels:
            mask[i,j,k] = False
            border_pixels.remove([i,j,k])

    io.imsave("tryout6.png",img)

Но он не вносит никаких изменений в изображение. Я получаю то же изображение, что и раньше, поэтому я попытался нанести пиксель границы на черное изображението же самое измерение для первой итерации, и я получаю следующий результат -
enter image description here

Я действительно понятия не имею, где я делаю неправильно здесь.

Ответы [ 2 ]

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

Вот решение, которое, я думаю, работает так, как вы просили (хотя я согласен с @Peter Boone, что это займет некоторое время). В моей реализации есть тройной цикл, но, может быть, кто-то другой сможет сделать это быстрее!

Сначала прочитайте изображение. В моем методе значения пикселей находятся в диапазоне от 0 до 1 (а не целые числа от 0 до 255).

import urllib
import matplotlib.pyplot as plt
import numpy as np
from skimage.morphology import  binary_dilation, binary_erosion, disk
from skimage.color import rgb2gray
from skimage.filters import threshold_otsu

# create a file-like object from the url
f = urllib.request.urlopen("https://i.stack.imgur.com/JXxJM.png")

# read the image file in a numpy array
# note that all pixel values are between 0 and 1 in this image
a = plt.imread(f)

Во-вторых, добавьте отступы по краям и пороговое значение изображения. Я использовал метод Оцу, но ответ @Peter Boone тоже хорошо работает.

# add black padding around image 100 px wide
a = np.pad(a, ((100,100), (100,100), (0,0)), mode = "constant")

# convert to greyscale and perform Otsu's thresholding
grayscale = rgb2gray(a)
global_thresh = threshold_otsu(grayscale)
binary_global1 = grayscale > global_thresh

# define number of pixels to expand the image
num_px_to_expand = 50

Изображение, binary_global1 - маска, которая выглядит следующим образом:

bw mask

Поскольку изображение состоит из трех каналов (RGB), я обрабатываю каналы отдельно. Я заметил, что мне нужно растереть изображение на ~ 5 px, потому что внешняя сторона изображения имеет некоторые необычные цвета и узоры.

# process each channel (RGB) separately
for channel in range(a.shape[2]):

    # select a single channel
    one_channel = a[:, :, channel]

    # reset binary_global for the each channel
    binary_global = binary_global1.copy()

    # erode by 5 px to get rid of unusual edges from original image
    binary_global = binary_erosion(binary_global, disk(5))

    # turn everything less than the threshold to 0
    one_channel = one_channel * binary_global

    # update pixels one at a time
    for jj in range(num_px_to_expand):

        # get 1 px ring of to update
        px_to_update = np.logical_xor(binary_dilation(binary_global, disk(1)), 
                                      binary_global)

        # update those pixels with the average of their neighborhood
        x, y = np.where(px_to_update == 1)

        for x, y in zip(x,y):
            # make 3 x 3 px slices
            slices = np.s_[(x-1):(x+2), (y-1):(y+2)]

            # update a single pixel
            one_channel[x, y] = (np.sum(one_channel[slices]*
                                             binary_global[slices]) / 
                                       np.sum(binary_global[slices]))      


        # update original image
        a[:,:, channel] = one_channel

        # increase binary_global by 1 px dilation
        binary_global = binary_dilation(binary_global, disk(1))

Когда я строю вывод, я получаю что-то вроде этого:

# plot image
plt.figure(figsize=[10,10])
plt.imshow(a)

final image

2 голосов
/ 23 октября 2019

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

Если вы сделаете что-то вроде этого:

image = io.imread("roi.jpg")
mask = image[:,:,0] < 30
just_inside = binary_dilation(mask) ^ mask
image[~just_inside] = [0,0,0]

, у вас будет маска, представляющая только пиксели внутри области интереса. Я также устанавливаю пиксели, не находящиеся в этой области, на 0,0,0.

Затем вы можете получить пиксели только за пределами roi:

just_outside = binary_erosion(mask) ^ mask

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

mean_blue = mean_bilateral(image[:,:,0], selem=square(3), s0=1, s1=255)
#etc...

Это не совсем правильно, но я думаю, что это должно направить вас в правильном направлении. Я бы проверил image.sc , если у вас есть более общие вопросы по обработке изображений. Дайте мне знать, если вам нужна дополнительная помощь, поскольку это было более общее направление, чем рабочий код.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...