I am trying to find boundary pixels of foreground object from binary image without using for loop. If anyone of the four neighbor of the specific pixel coordinate is zero and that pixel value is one, I will assign it as a boundary pixel. It works fine with for loop but I don't want to use a loop so is there anything I can do with it. Here is the code:
for i in range(len(PCR)):
cr_h = PCR[i,0]
cr_w = PCR[i,1]
n1 = img_cap_copy[cr_h-1,cr_w]
n2 = img_cap_copy[cr_h+1,cr_w]
n3 = img_cap_copy[cr_h,cr_w-1]
n4 = img_cap_copy[cr_h,cr_w+1]
n=[n1,n2,n3,n4]
if img_cap_copy[cr_h,cr_w]==1 and (n[0]==0 or n[1]==0 or n[2]==0 or n[3]==0):
Xc.append(cr_w)
Yc.append(cr_h)
This is what I am trying to do without for loop which is giving me error'The truth value of an array with more than one element is ambiguous. Use a.any() or a.all().'
cr_h=PCR[:,0]
cr_h=PCR[:,0]
n1 = img_cap_copy[cr_h-1,cr_w]
n2 = img_cap_copy[cr_h+1,cr_w]
n3 = img_cap_copy[cr_h,cr_w-1]
n4 = img_cap_copy[cr_h,cr_w+1]
n=[n1,n2,n3,n4]
if img_cap_copy[cr_h,cr_w]==1 and (n[0]==0 or n[1]==0 or n[2]==0 or n[3]==0):
Xc.append(cr_w)
Yc.append(cr_h)
You may use np.logical_or
and np.logical_and
and logical indexing as follows:
cr_h=PCR[:,0]
cr_w=PCR[:,1] #cr_h=PCR[:,0]
n1 = img_cap_copy[cr_h-1,cr_w]
n2 = img_cap_copy[cr_h+1,cr_w]
n3 = img_cap_copy[cr_h,cr_w-1]
n4 = img_cap_copy[cr_h,cr_w+1]
# Logical array with True where condition is met
c = np.logical_and(img_cap_copy[cr_h,cr_w]==1, np.logical_or(np.logical_or(np.logical_or(n1==0, n2==0), n3==0), n4==0))
# Use logical indexing - return elements when c is True.
Xc = cr_w[c].tolist()
Yc = cr_h[c].tolist()
Testing code:
import cv2
import numpy as np
# Build sample image
img = np.random.randint(0, 255, (120, 160), np.uint8)
img_cap_copy = np.minimum(cv2.threshold(img, 50, 255, cv2.THRESH_BINARY)[1], 1)
# Build sample PRC
PCR = np.vstack((np.r_[1:1001], np.r_[10:1010])).T % 100
# Used as reference
refXc = []
refYc = []
for i in range(len(PCR)):
cr_h = PCR[i,0]
cr_w = PCR[i,1]
n1 = img_cap_copy[cr_h-1,cr_w]
n2 = img_cap_copy[cr_h+1,cr_w]
n3 = img_cap_copy[cr_h,cr_w-1]
n4 = img_cap_copy[cr_h,cr_w+1]
n=[n1,n2,n3,n4]
if img_cap_copy[cr_h,cr_w]==1 and (n[0]==0 or n[1]==0 or n[2]==0 or n[3]==0):
refXc.append(cr_w)
refYc.append(cr_h)
cr_h=PCR[:,0]
cr_w=PCR[:,1] #cr_h=PCR[:,0]
n1 = img_cap_copy[cr_h-1,cr_w]
n2 = img_cap_copy[cr_h+1,cr_w]
n3 = img_cap_copy[cr_h,cr_w-1]
n4 = img_cap_copy[cr_h,cr_w+1]
# Logical array with True where condition is met
c = np.logical_and(img_cap_copy[cr_h,cr_w]==1, np.logical_or(np.logical_or(np.logical_or(n1==0, n2==0), n3==0), n4==0))
# Use logical indexing - return elements when c is True.
Xc = cr_w[c].tolist()
Yc = cr_h[c].tolist()
print(str(np.all(np.array(Xc) == np.array(refXc))))
print(str(np.all(np.array(Yc) == np.array(refYc))))
Note:
img_cap_copy
has only ones and zeros, you may use math instead of logical operations, but using np.logical_or
and np.logical_and
is closer to your original loop code.