I am trying to perform pixel by pixel operations on the image but it is painfully slow. It is taking 7-8 hours for a single image of dimension(512*512) and I have images upto 2048*2048.
I have also tried it optimising using Numba but it is taking the same time due to the presence of plenty of pyobjects
which is according to this tutorial is bad as numba is not able to translate the variables into something it understands and hence optimise.
Below is the short version of my question, I have enclosed the complete details So, now I am trying to use cython by following this tutorial. Following is my code, which I am trying to optimise-
img = Image.open(path_dir)
pixelMap = img.load()
roi = []
for i in range(img.size[0]):
for j in range(img.size[1]):
if pix[i,j] == 255:
roi.append([i,j])
notroi = img.size[0]*img.size[1] - len(roi)
Above this, it doesn't take much time and I don't need to modify it.
def roifun(img,roi,notroi,newmap,pix):
while(notroi):
border_pixels = []
h = img.size[0]
w = img.size[1]
for i in range(0,h): //---1
for j in range(0,w):
if [i,j] 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):
border_pixels.append([i,j])
for (each_i,each_j) in border_pixels: //---2
color_sum = 0
count = 1
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 (pix_i,pix_j) in roi:
color_sum+=pix[pix_i,pix_j]
count+=1
newmap[each_i,each_j]=(color_sum//count)
for (i,j) in border_pixels: //----3
roi.append([i,j])
border_pixels.remove([i,j])
notroi = notroi-1
print(notroi)
Now, I just broke the problem of converting the above code to cython in 3 parts(according to their for loops) for easy debugging.
I converted the first loop in the following way-
%%cython -a
import cython
cimport numpy as np
# @cython.boundscheck(False)
cpdef border(img,roi):
border_pixels = []
cdef long h,w,i,j
h = img.shape[0]
w = img.shape[1]
for i in range(0,h):
for j in range(0,w):
if [i,j] 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):
border_pixels.append([i,j])
Issue I faced-
1)Getting TypeError: a bytes-like object is required, not 'list'
while calling the border
function.
I don't know why it expects the list to be in byte like object
and how to do it.
2)I don't know how to convert the image in cython way, I tried converting it into char[:,:]
but then got the error TypeError: a bytes-like object is required, not 'GIFImageFile
.
In the second loop, I'll have the same problem but now I have to also try to convert pix
which is a pixel object
.
In case, if you guys are wondering what I am trying to achieve, complete details are in this question.
Expanding the Region of interest of an image
Any other way without cython is also appreciated.
I would definitely look into using scikit-image or at least using numpy for anything where you need to process pixels in an image. It will take way too long in pure python.
To reproduce your first bit of code with skimage, I would do this:
from skimage import io
img = io.imread(path_dir)
mask = img == 255
This will give you a numpy array of True/False values where the pixels are equal to 255. Then you could dilate that mask to get an expanded region of interest.