Vaduva Mihaita Bogdan
Vaduva Mihaita Bogdan

Reputation: 170

Region growing implementation in python, without seeding

I am trying to implement the region growing segmentation algorithm in python, but I am not allowed to use seed points. My idea so far is this:

Start from the very first pixel, verify its neighbors for boundaries check (within width and height), then verify the neighbors so that they are within the threshold (I obtained this by using the euclidean distance between the current pixel and the neighbor). To be made sure that I don't visit the same pixel again, I created a matrix with the same dimensions as the image (width, height) and made all elements 0 in the beginning. I will start from currentArea number 1 and increment as it goes. In the end, after obaining all areas with their respective average colors, I will use a function that writes down the new Image based on the tuples I have obtained. (averagePixelColor, areaNumber)

This is my code:

from PIL import Image
from scipy.spatial import distance
import statistics
import numpy as np
import sys
sys.setrecursionlimit(10**9)
# SCRIPT: color palette reduction applier script
# SCRIPT: this is the second method. region growing segmentation

# list of red values of pixels
rList = []
# list of green values of pixels
gList = []
# list of blue values of pixels
bList = []
# this matrix will be initially 0, then every region growth
# will be updated to its number
overlayMatrix = []
# starting area number
currentArea = 1

def isValidPixel(x, y, width, height):
    if x < 0 or x >= width:
        return False
    if y < 0 or y >= height:
        return False

    return True

def get_average_color():

    global rList
    global gList
    global bList

    # set values to none
    r = None
    g = None
    b = None

    # get average value for each chanel
    if rList != []:
        r = sum(rList)/len(rList)
        g = sum(gList)/len(gList)
        b = sum(bList)/len(bList)

        # make values integers to be used as pixel
        r = int(r)
        g = int(g)
        b = int(b)

    # return values
    return (r, g, b)

def add_pixel_to_lists(pixel):
    global rList
    global gList
    global bList

    rList.append(pixel[0])
    gList.append(pixel[1])
    bList.append(pixel[2])

def region_growing(x, y, pixel, img, currentArea):
    global overlayMatrix
    global rList
    global gList
    global bList
    # get width, heihgt
    width, height = img.size
    # set this pixel to be visited on current area
    overlayMatrix[x][y] = currentArea
    # set a list for all possible neighbours
    neighbouringPixels = [(x-1, y), (x-1, y-1), (x-1, y+1), (x, y-1), (x, y+1), (x+1, y), (x+1, y-1), (x+1, y+1)]
    # filter to get only valid neighbours
    validPixels = [x for x in neighbouringPixels if isValidPixel(x[0], x[1], width, height) == True]

    # filter pixels to be not visited
    notVisitedPixels = [x for x in validPixels if overlayMatrix[x[0]][x[1]] == 0]

    # set a threshold value
    threshold = 5

    # filter to get only pixels in threshold
    thresholdPixels = []
    thresholdPixels = [x for x in notVisitedPixels if distance.euclidean(img.getpixel(x), pixel) < threshold]

    # set the list for pixels to make recursive calls
    toVisitRecursive = []

    # for every pixel that is a valid neighbour, add it to the toVisit list in recursive call
    # and add its rgb values to the lists so an average can be computed
    for pixel in thresholdPixels:
        toVisitRecursive.append(pixel)
        add_pixel_to_lists(img.getpixel(pixel))

    # compute average
    averagePixel = get_average_color()

    # if I still have neighoburs that haven't been visited
    # and are within the threshold, get first from list
    # remove it so we don't do the same again, then apply
    # the algorithm for it
    if toVisitRecursive != []:
        pixel = toVisitRecursive[0]
        toVisitRecursive.remove(pixel)
        region_growing(pixel[0], pixel[1], averagePixel, img, currentArea)

    # finally, return
    return (averagePixel, currentArea+1)


def write_image():
    pass
    # this will write to the image based on the list of tuples
    # average color to the area with number X

def palette_reduction_mt2(input_image):
    # open original image
    img = Image.open(input_image)
    tuple_list = []
    # get width, height
    width, height = img.size

    # make overlay matrix of 0, initial
    global overlayMatrix
    overlayMatrix = np.zeros((width, height), dtype=np.int32)
    # create new image
    newimg = Image.new("RGB", (width, height), "white")
    currentArea = 1
    # iterate through image pixels
    for y in range(0, height-1):
        for x in range(0, width-1):
            global rList
            global gList
            global bList

            # get pixel from edge image
            p = img.getpixel((x, y))
            # apply region growing

            average, currentArea = region_growing(x, y, p, img, currentArea)
            tuple_list.append((average, currentArea-1))

            # reset color lists to compute new average
            rList = []
            gList = []
            bList = []
    print(tuple_list)
    # Save image
    newimg.save("images/reduced_mt1.jpg")
    # return the name of the image
    return "images/reduced_mt1.jpg"

For some reason, when I print the tuples list, I only get a single value: [(0,0,0), 1]

Can anyone please point me in the right direction?

Thank you!

Upvotes: 1

Views: 3502

Answers (1)

rafaelcastrocouto
rafaelcastrocouto

Reputation: 12161

Seems like you are not actually iterating over the toVisitRecursive list. Maybe you should add a loop like:

 for pixel in toVisitRecursive:
   // region_growing...

or change this line if toVisitRecursive != []: for a while loop;

Upvotes: 1

Related Questions