Finding particular boxes in an Image using openCV



.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;








1















I have the following image:
enter image description here



from which I want to extract the boxes inside which a triangle is shown. I did it using simple vertical and horizontal line detection, which takes a total of 10 seconds on my machine.



Now, since this has to be done a lot of times, efficiency is of great concern. So, is there any method in openCV (or anywhere else) that can extract these boxes efficiently? Here an efficient method that takes less time than the brute force approach would suffice.



Any help is appreciated!



My approach:



I've made a function searchHorizontalLinesX that is used to search lines of particular lengths. It does so by going through every pixel once. My image has the dimensions: 2479 x 3504 = 8686416 pixels. (The image attached is of low quality, since the upload limit is 2MB. The image I am using is of more than 16 MB)



So, I input the width of the whole box (L1), and the width of box numbered 5(L2). Now, the function returns lines that have L1 length and L2 length. So, all the ones having L1 lengths can be used to extract boxes 1,2,3,4,6,7,8,9 and 10.



Once the lines are found, I search for the lines that have a difference of H between them, where H is the height of each box, for each box. Using these I get the boxes.



For the boxes that aren't the whole column that was extracted then I try to find a line that goes from the top to the bottom and then extract the image on the relevant side of the line.



def searchHorizontalLinesX(im,lengths,pg,gap=10):
"""
im: PIL image object of the file
lengths: list of lengths of lines to recognize
pg: Page number of the page to take under consideration
"""
im.seek(pg)
dimX = im.size[0]
dimY = im.size[1]
pix = im.load()
line = False
n = len(lengths)
linez = [ for i in range(0,n)]
for j in range(0,dimY):
for i in range(0,dimX):
if(line):
if(pix[i,j][0]!=0 or pix[i,j][1]!=255):
line = False
end = (i-1,j)
for num,l in enumerate(lengths):
if(end[0]-start[0]>(l-gap) and end[0]-start[0]<(l+gap)):
linez[num].append([start,end])
elif(start[1]==j-1 and i==0):#End to end line
end = (im.size[0],start[1])
line = False
for i,l in enumerate(lengths):
if(end[0]-start[0]>(l-gap) and end[0]-start[0]<(l+gap)):
linez[num].append([start,end])
else:
if(pix[i,j][0]==0 or pix[i,j][1]==255):
start = (i,j)
line = True
return linez

def searchVerticalLines(im,length,pg,gap=5):
"""
im: PIL image object of the file
length: Length of box
dimX: Width of the page
dimY: Height of the page
pg: Page number of the page to take under consideration
"""
im.seek(pg)
dimX = im.size[0]
dimY = im.size[1]
pix = im.load()
line = False
linez =
start = (0,0)
end = (0,0)
for i in range(0,dimX):
for j in range(0,dimY):
if(line):
if(pix[i,j][0]!=0 or pix[i,j][1]!=255):
line = False
end = (i,j-1)
if(end[1]-start[1]>(length-gap) and end[1]-start[1]<(length+gap)):
linez.append([start,end])
elif(start[0]==i-1 and j==0):
line = False
end = (start[0],im.size[1])
if(end[1]-start[1]>(length-gap) and end[1]-start[1]<(length+gap)):
linez.append([start,end])

else:
if(pix[i,j][0]==0 or pix[i,j][1]==255):
start = (i,j)
line = True
return linez

def grouping(hor,width):
"""
Groups similar horizontal lines together.
hor: List of lines in the format [[(start_x,start_y),(end_x,end_y)],...]
width: What width can a line have. Takes all the lines inside this list into a group
Returns: A list of groups. Each group is a list of lines. Each line has the format [(start_x,start_y),(end_x,end_y)]
"""
horSet = set()
for i in hor:
horSet.add((i[0],i[1]))
group =
count = 0
for i in hor:
if (i[0],i[1]) in horSet:
print("Visiting :"+str(i))
for j in hor:
if (j[0],j[1]) in horSet:
if(i[0][0]==j[0][0] and i[1][0]==j[1][0] and abs(j[0][1]-i[0][1])<width and abs(j[1][1]-i[1][1])<width):
if(len(group)<=count):
group.append([j])
else:
group[count].append(j)
horSet.remove((j[0],j[1]))
count+=1
return group
def groupingH(ver,width,heightDifference = 2):
"""
Groups similar vertical lines together.
hor: List of lines in the format [[(start_x,start_y),(end_x,end_y)],...]
width: What width can a line have. Takes all the lines inside this list into a group
Returns: A list of groups. Each group is a list of lines. Each line has the format [(start_x,start_y),(end_x,end_y)]
"""
verSet = set()
for i in ver:
verSet.add((i[0],i[1]))
group =
count = 0
for i in ver:
if (i[0],i[1]) in verSet:
for j in ver:
if (abs(i[0][1]-j[0][1])< heightDifference and abs(i[1][1]-j[1][1])< heightDifference and abs(j[0][0]-i[0][0])<width and abs(j[1][0]-i[1][0])<width):
if(len(group)<=count):
group.append([j])
else:
group[count].append(j)
verSet.remove((j[0],j[1]))
count+=1
return group




def boxing(groupList,boxHeight,gap=5,lw=4):
"""
Given a groupList, it makes a list of coordinates of boxes that have a boxHeight height+-5
"""
boxCoord =
groupSet = set()
for i in range(len(groupList)):
groupSet.add(i)
for i,g in enumerate(groupList):
if i in groupSet:
print("On :"+str(i))
for j,g1 in enumerate(groupList):
if j in groupSet:
print(" Checking :"+str(j))
if(g[0][0][0]==g1[0][0][0] and g[0][1][0]==g1[0][1][0] and abs(g[len(g)-1][0][1]-g1[0][0][1])>=boxHeight-gap and abs(g[len(g)-1][0][1]-g1[0][0][1])<boxHeight+gap):
groupSet.remove(j)
print(" removing :"+str(j))
boxCoord.append((g[0][0][0]+lw,min(g[len(g)-1][0][1],g1[0][0][1])+1,g[0][1][0]-lw,max(g[len(g)-1][0][1],g1[0][0][1])-1))
break
groupSet.remove(i)
return boxCoord

##############################
def getFrontPageBoxes(im,pg,coords,margin=10):
"""
coords[0]: List of lengths of horizontal lines to be recognized: 0th for box1, 1st for box2+3 (and 4,5,6,7,8,9,10)
coords[1]: Height of box 1
coords[2]: Height of box 2,3
coords[3]: Height of box 4,5,6,7
coords[4]: Height of box 8,10
coords[5]: Height of box 9
"""
# Box 1: Police station... et cetera.
t =
t1 = t.append(time())
linez = searchHorizontalLinesX(im,coords[0],0) #0 for box 1 <-- Takes time
t2 = t.append(time())
groupForBox1 = grouping(linez[0],4)
leftUpperCorner = groupForBox1[0][len(groupForBox1[0])-1][0]
t3 = t.append(time())
verLinez = searchVerticalLines(im,coords[1],0,10) # <-- Takes time
t4 = t.append(time())
rightLowerCorner = verLinez[0][1]
box1 = im.crop((leftUpperCorner[0]+margin,leftUpperCorner[1]+margin,linez[0][0][1][0]-margin,rightLowerCorner[1]-margin))
# Box 2+3: Polling station name and address
groupForBox2 = grouping(linez[1],4)
bxesFor2 = boxing(groupForBox2,coords[2])
box2Uncropped = im.crop(bxesFor2[len(bxesFor2)-1]) # The last one is the one we want
t5 = t.append(time())
verLinesFor2 = searchVerticalLines(box2Uncropped,box2Uncropped.size[1],0,10) # <-- Takes time
t6 = t.append(time())
group2ForBox2 = groupingH(verLinesFor2,4)
leftUpperCorner = (0,0)
rightLowerCorner = group2ForBox2[0][0][1]
box2 = box2Uncropped.crop((leftUpperCorner[0]+margin,leftUpperCorner[1]+margin,rightLowerCorner[0]-margin,rightLowerCorner[1]-margin))
# Box 4,5,6,7:
groupForBox4 = groupForBox2
bxesFor4 = boxing(groupForBox4,coords[3])
box4Uncropped = im.crop(bxesFor4[0])
t7 = t.append(time())
verLinesFor4 = searchVerticalLines(box4Uncropped,box4Uncropped.size[1],0,10) # <-- Takes time
t8 = t.append(time())
group2ForBox4 = groupingH(verLinesFor4,4)
#There must be 5 groups.

# Error raising mechanism needed here
maleBox = box4Uncropped.crop((group2ForBox4[1][len(group2ForBox4[1])-1][0][0]+margin,0+margin,group2ForBox4[2][0][0][0]-margin,box4Uncropped.size[1]-margin))
femaleBox = box4Uncropped.crop((group2ForBox4[2][len(group2ForBox4[2])-1][0][0]+margin,0+margin,group2ForBox4[3][0][0][0]-margin,box4Uncropped.size[1]-margin))
third_gender = box4Uncropped.crop((group2ForBox4[3][len(group2ForBox4[3])-1][0][0]+margin,0+margin,group2ForBox4[4][0][0][0]-margin,box4Uncropped.size[1]-margin))
total = box4Uncropped.crop((group2ForBox4[4][len(group2ForBox4[4])-1][0][0]+margin,0+margin,box4Uncropped.size[0]-margin,box4Uncropped.size[1]-margin))

# Box 8, 10:
groupForBox8 = groupForBox2
bxesFor8 = boxing(groupForBox8,coords[4])
box8Uncropped = im.crop(bxesFor8[0])
t9 = t.append(time())
verLinesFor8 = searchVerticalLines(box8Uncropped,box8Uncropped.size[1],0,10) # <--Takes time
t10 = t.append(time())
group2ForBox8 = groupingH(verLinesFor8,4)
box10 = box8Uncropped.crop((group2ForBox8[0][len(group2ForBox8)-1][0][0]+margin,0+margin,box8Uncropped.size[0]-margin,box8Uncropped.size[1]-margin))
box8 = box8Uncropped.crop((0+margin,0+margin,group2ForBox8[0][0][0][0]-margin,box8Uncropped.size[1]-margin))

# Box 9:
groupForBox9 = groupForBox2
bxesFor9= boxing(groupForBox9,coords[5])
box9 = im.crop((bxesFor9[0][0]+margin,bxesFor9[0][1]+margin,bxesFor9[0][2]-margin,bxesFor9[0][3]-margin))
for i in range(0,len(t)-1):
print('Time taken :'+str(t[i+1]-t[i]))
return [box1,box2,maleBox,femaleBox,third_gender,total,box8,box9,box10]
def processBoxes(bxLst):
opList =
for i,box in enumerate(bxLst):
print("box :"+str(i))
opList.append(pt.image_to_string(box,lang='hin+eng',config='--psm 6'))
return opList

def getFrontPageInfo(im,pg,coords):
"""
coords[0]: List of lengths of horizontal lines to be recognized: 0th for box1, 1st for box2+3,
2nd for boxes 4,5,6,7, 3rd for boxes 8 and 10, 4th for box 9
coords[1]: List of lengths of vertical lines to be recognized: 0th for box1
coords[2]: Height of box 2,3
coords[3]: Height of box 4,5,6,7
coords[4]: Height of box 8,10
coords[5]: Height of box 9
"""
boxList = getFrontPageBoxes(im,pg,coords)
return processBoxes(boxList)









share|improve this question
























  • Unfortunately, 10 seconds on my machine is not enough information to work on optimization problem.

    – Rick M.
    Nov 15 '18 at 16:28











  • @RickM Does the code help?

    – Mooncrater
    Nov 15 '18 at 17:08






  • 1





    Get a faster machine?

    – barny
    Nov 16 '18 at 0:34






  • 3





    I think if you're working with a specific type of document like this and want to get the information in some certain boxes, you should create maskes of where those boxes located in the document, then you only need to detect the document in the image and apply those maskes in.

    – Ha Bom
    Nov 16 '18 at 3:16











  • @HaBom Can you help me find some resources?

    – Mooncrater
    Nov 17 '18 at 3:25

















1















I have the following image:
enter image description here



from which I want to extract the boxes inside which a triangle is shown. I did it using simple vertical and horizontal line detection, which takes a total of 10 seconds on my machine.



Now, since this has to be done a lot of times, efficiency is of great concern. So, is there any method in openCV (or anywhere else) that can extract these boxes efficiently? Here an efficient method that takes less time than the brute force approach would suffice.



Any help is appreciated!



My approach:



I've made a function searchHorizontalLinesX that is used to search lines of particular lengths. It does so by going through every pixel once. My image has the dimensions: 2479 x 3504 = 8686416 pixels. (The image attached is of low quality, since the upload limit is 2MB. The image I am using is of more than 16 MB)



So, I input the width of the whole box (L1), and the width of box numbered 5(L2). Now, the function returns lines that have L1 length and L2 length. So, all the ones having L1 lengths can be used to extract boxes 1,2,3,4,6,7,8,9 and 10.



Once the lines are found, I search for the lines that have a difference of H between them, where H is the height of each box, for each box. Using these I get the boxes.



For the boxes that aren't the whole column that was extracted then I try to find a line that goes from the top to the bottom and then extract the image on the relevant side of the line.



def searchHorizontalLinesX(im,lengths,pg,gap=10):
"""
im: PIL image object of the file
lengths: list of lengths of lines to recognize
pg: Page number of the page to take under consideration
"""
im.seek(pg)
dimX = im.size[0]
dimY = im.size[1]
pix = im.load()
line = False
n = len(lengths)
linez = [ for i in range(0,n)]
for j in range(0,dimY):
for i in range(0,dimX):
if(line):
if(pix[i,j][0]!=0 or pix[i,j][1]!=255):
line = False
end = (i-1,j)
for num,l in enumerate(lengths):
if(end[0]-start[0]>(l-gap) and end[0]-start[0]<(l+gap)):
linez[num].append([start,end])
elif(start[1]==j-1 and i==0):#End to end line
end = (im.size[0],start[1])
line = False
for i,l in enumerate(lengths):
if(end[0]-start[0]>(l-gap) and end[0]-start[0]<(l+gap)):
linez[num].append([start,end])
else:
if(pix[i,j][0]==0 or pix[i,j][1]==255):
start = (i,j)
line = True
return linez

def searchVerticalLines(im,length,pg,gap=5):
"""
im: PIL image object of the file
length: Length of box
dimX: Width of the page
dimY: Height of the page
pg: Page number of the page to take under consideration
"""
im.seek(pg)
dimX = im.size[0]
dimY = im.size[1]
pix = im.load()
line = False
linez =
start = (0,0)
end = (0,0)
for i in range(0,dimX):
for j in range(0,dimY):
if(line):
if(pix[i,j][0]!=0 or pix[i,j][1]!=255):
line = False
end = (i,j-1)
if(end[1]-start[1]>(length-gap) and end[1]-start[1]<(length+gap)):
linez.append([start,end])
elif(start[0]==i-1 and j==0):
line = False
end = (start[0],im.size[1])
if(end[1]-start[1]>(length-gap) and end[1]-start[1]<(length+gap)):
linez.append([start,end])

else:
if(pix[i,j][0]==0 or pix[i,j][1]==255):
start = (i,j)
line = True
return linez

def grouping(hor,width):
"""
Groups similar horizontal lines together.
hor: List of lines in the format [[(start_x,start_y),(end_x,end_y)],...]
width: What width can a line have. Takes all the lines inside this list into a group
Returns: A list of groups. Each group is a list of lines. Each line has the format [(start_x,start_y),(end_x,end_y)]
"""
horSet = set()
for i in hor:
horSet.add((i[0],i[1]))
group =
count = 0
for i in hor:
if (i[0],i[1]) in horSet:
print("Visiting :"+str(i))
for j in hor:
if (j[0],j[1]) in horSet:
if(i[0][0]==j[0][0] and i[1][0]==j[1][0] and abs(j[0][1]-i[0][1])<width and abs(j[1][1]-i[1][1])<width):
if(len(group)<=count):
group.append([j])
else:
group[count].append(j)
horSet.remove((j[0],j[1]))
count+=1
return group
def groupingH(ver,width,heightDifference = 2):
"""
Groups similar vertical lines together.
hor: List of lines in the format [[(start_x,start_y),(end_x,end_y)],...]
width: What width can a line have. Takes all the lines inside this list into a group
Returns: A list of groups. Each group is a list of lines. Each line has the format [(start_x,start_y),(end_x,end_y)]
"""
verSet = set()
for i in ver:
verSet.add((i[0],i[1]))
group =
count = 0
for i in ver:
if (i[0],i[1]) in verSet:
for j in ver:
if (abs(i[0][1]-j[0][1])< heightDifference and abs(i[1][1]-j[1][1])< heightDifference and abs(j[0][0]-i[0][0])<width and abs(j[1][0]-i[1][0])<width):
if(len(group)<=count):
group.append([j])
else:
group[count].append(j)
verSet.remove((j[0],j[1]))
count+=1
return group




def boxing(groupList,boxHeight,gap=5,lw=4):
"""
Given a groupList, it makes a list of coordinates of boxes that have a boxHeight height+-5
"""
boxCoord =
groupSet = set()
for i in range(len(groupList)):
groupSet.add(i)
for i,g in enumerate(groupList):
if i in groupSet:
print("On :"+str(i))
for j,g1 in enumerate(groupList):
if j in groupSet:
print(" Checking :"+str(j))
if(g[0][0][0]==g1[0][0][0] and g[0][1][0]==g1[0][1][0] and abs(g[len(g)-1][0][1]-g1[0][0][1])>=boxHeight-gap and abs(g[len(g)-1][0][1]-g1[0][0][1])<boxHeight+gap):
groupSet.remove(j)
print(" removing :"+str(j))
boxCoord.append((g[0][0][0]+lw,min(g[len(g)-1][0][1],g1[0][0][1])+1,g[0][1][0]-lw,max(g[len(g)-1][0][1],g1[0][0][1])-1))
break
groupSet.remove(i)
return boxCoord

##############################
def getFrontPageBoxes(im,pg,coords,margin=10):
"""
coords[0]: List of lengths of horizontal lines to be recognized: 0th for box1, 1st for box2+3 (and 4,5,6,7,8,9,10)
coords[1]: Height of box 1
coords[2]: Height of box 2,3
coords[3]: Height of box 4,5,6,7
coords[4]: Height of box 8,10
coords[5]: Height of box 9
"""
# Box 1: Police station... et cetera.
t =
t1 = t.append(time())
linez = searchHorizontalLinesX(im,coords[0],0) #0 for box 1 <-- Takes time
t2 = t.append(time())
groupForBox1 = grouping(linez[0],4)
leftUpperCorner = groupForBox1[0][len(groupForBox1[0])-1][0]
t3 = t.append(time())
verLinez = searchVerticalLines(im,coords[1],0,10) # <-- Takes time
t4 = t.append(time())
rightLowerCorner = verLinez[0][1]
box1 = im.crop((leftUpperCorner[0]+margin,leftUpperCorner[1]+margin,linez[0][0][1][0]-margin,rightLowerCorner[1]-margin))
# Box 2+3: Polling station name and address
groupForBox2 = grouping(linez[1],4)
bxesFor2 = boxing(groupForBox2,coords[2])
box2Uncropped = im.crop(bxesFor2[len(bxesFor2)-1]) # The last one is the one we want
t5 = t.append(time())
verLinesFor2 = searchVerticalLines(box2Uncropped,box2Uncropped.size[1],0,10) # <-- Takes time
t6 = t.append(time())
group2ForBox2 = groupingH(verLinesFor2,4)
leftUpperCorner = (0,0)
rightLowerCorner = group2ForBox2[0][0][1]
box2 = box2Uncropped.crop((leftUpperCorner[0]+margin,leftUpperCorner[1]+margin,rightLowerCorner[0]-margin,rightLowerCorner[1]-margin))
# Box 4,5,6,7:
groupForBox4 = groupForBox2
bxesFor4 = boxing(groupForBox4,coords[3])
box4Uncropped = im.crop(bxesFor4[0])
t7 = t.append(time())
verLinesFor4 = searchVerticalLines(box4Uncropped,box4Uncropped.size[1],0,10) # <-- Takes time
t8 = t.append(time())
group2ForBox4 = groupingH(verLinesFor4,4)
#There must be 5 groups.

# Error raising mechanism needed here
maleBox = box4Uncropped.crop((group2ForBox4[1][len(group2ForBox4[1])-1][0][0]+margin,0+margin,group2ForBox4[2][0][0][0]-margin,box4Uncropped.size[1]-margin))
femaleBox = box4Uncropped.crop((group2ForBox4[2][len(group2ForBox4[2])-1][0][0]+margin,0+margin,group2ForBox4[3][0][0][0]-margin,box4Uncropped.size[1]-margin))
third_gender = box4Uncropped.crop((group2ForBox4[3][len(group2ForBox4[3])-1][0][0]+margin,0+margin,group2ForBox4[4][0][0][0]-margin,box4Uncropped.size[1]-margin))
total = box4Uncropped.crop((group2ForBox4[4][len(group2ForBox4[4])-1][0][0]+margin,0+margin,box4Uncropped.size[0]-margin,box4Uncropped.size[1]-margin))

# Box 8, 10:
groupForBox8 = groupForBox2
bxesFor8 = boxing(groupForBox8,coords[4])
box8Uncropped = im.crop(bxesFor8[0])
t9 = t.append(time())
verLinesFor8 = searchVerticalLines(box8Uncropped,box8Uncropped.size[1],0,10) # <--Takes time
t10 = t.append(time())
group2ForBox8 = groupingH(verLinesFor8,4)
box10 = box8Uncropped.crop((group2ForBox8[0][len(group2ForBox8)-1][0][0]+margin,0+margin,box8Uncropped.size[0]-margin,box8Uncropped.size[1]-margin))
box8 = box8Uncropped.crop((0+margin,0+margin,group2ForBox8[0][0][0][0]-margin,box8Uncropped.size[1]-margin))

# Box 9:
groupForBox9 = groupForBox2
bxesFor9= boxing(groupForBox9,coords[5])
box9 = im.crop((bxesFor9[0][0]+margin,bxesFor9[0][1]+margin,bxesFor9[0][2]-margin,bxesFor9[0][3]-margin))
for i in range(0,len(t)-1):
print('Time taken :'+str(t[i+1]-t[i]))
return [box1,box2,maleBox,femaleBox,third_gender,total,box8,box9,box10]
def processBoxes(bxLst):
opList =
for i,box in enumerate(bxLst):
print("box :"+str(i))
opList.append(pt.image_to_string(box,lang='hin+eng',config='--psm 6'))
return opList

def getFrontPageInfo(im,pg,coords):
"""
coords[0]: List of lengths of horizontal lines to be recognized: 0th for box1, 1st for box2+3,
2nd for boxes 4,5,6,7, 3rd for boxes 8 and 10, 4th for box 9
coords[1]: List of lengths of vertical lines to be recognized: 0th for box1
coords[2]: Height of box 2,3
coords[3]: Height of box 4,5,6,7
coords[4]: Height of box 8,10
coords[5]: Height of box 9
"""
boxList = getFrontPageBoxes(im,pg,coords)
return processBoxes(boxList)









share|improve this question
























  • Unfortunately, 10 seconds on my machine is not enough information to work on optimization problem.

    – Rick M.
    Nov 15 '18 at 16:28











  • @RickM Does the code help?

    – Mooncrater
    Nov 15 '18 at 17:08






  • 1





    Get a faster machine?

    – barny
    Nov 16 '18 at 0:34






  • 3





    I think if you're working with a specific type of document like this and want to get the information in some certain boxes, you should create maskes of where those boxes located in the document, then you only need to detect the document in the image and apply those maskes in.

    – Ha Bom
    Nov 16 '18 at 3:16











  • @HaBom Can you help me find some resources?

    – Mooncrater
    Nov 17 '18 at 3:25













1












1








1








I have the following image:
enter image description here



from which I want to extract the boxes inside which a triangle is shown. I did it using simple vertical and horizontal line detection, which takes a total of 10 seconds on my machine.



Now, since this has to be done a lot of times, efficiency is of great concern. So, is there any method in openCV (or anywhere else) that can extract these boxes efficiently? Here an efficient method that takes less time than the brute force approach would suffice.



Any help is appreciated!



My approach:



I've made a function searchHorizontalLinesX that is used to search lines of particular lengths. It does so by going through every pixel once. My image has the dimensions: 2479 x 3504 = 8686416 pixels. (The image attached is of low quality, since the upload limit is 2MB. The image I am using is of more than 16 MB)



So, I input the width of the whole box (L1), and the width of box numbered 5(L2). Now, the function returns lines that have L1 length and L2 length. So, all the ones having L1 lengths can be used to extract boxes 1,2,3,4,6,7,8,9 and 10.



Once the lines are found, I search for the lines that have a difference of H between them, where H is the height of each box, for each box. Using these I get the boxes.



For the boxes that aren't the whole column that was extracted then I try to find a line that goes from the top to the bottom and then extract the image on the relevant side of the line.



def searchHorizontalLinesX(im,lengths,pg,gap=10):
"""
im: PIL image object of the file
lengths: list of lengths of lines to recognize
pg: Page number of the page to take under consideration
"""
im.seek(pg)
dimX = im.size[0]
dimY = im.size[1]
pix = im.load()
line = False
n = len(lengths)
linez = [ for i in range(0,n)]
for j in range(0,dimY):
for i in range(0,dimX):
if(line):
if(pix[i,j][0]!=0 or pix[i,j][1]!=255):
line = False
end = (i-1,j)
for num,l in enumerate(lengths):
if(end[0]-start[0]>(l-gap) and end[0]-start[0]<(l+gap)):
linez[num].append([start,end])
elif(start[1]==j-1 and i==0):#End to end line
end = (im.size[0],start[1])
line = False
for i,l in enumerate(lengths):
if(end[0]-start[0]>(l-gap) and end[0]-start[0]<(l+gap)):
linez[num].append([start,end])
else:
if(pix[i,j][0]==0 or pix[i,j][1]==255):
start = (i,j)
line = True
return linez

def searchVerticalLines(im,length,pg,gap=5):
"""
im: PIL image object of the file
length: Length of box
dimX: Width of the page
dimY: Height of the page
pg: Page number of the page to take under consideration
"""
im.seek(pg)
dimX = im.size[0]
dimY = im.size[1]
pix = im.load()
line = False
linez =
start = (0,0)
end = (0,0)
for i in range(0,dimX):
for j in range(0,dimY):
if(line):
if(pix[i,j][0]!=0 or pix[i,j][1]!=255):
line = False
end = (i,j-1)
if(end[1]-start[1]>(length-gap) and end[1]-start[1]<(length+gap)):
linez.append([start,end])
elif(start[0]==i-1 and j==0):
line = False
end = (start[0],im.size[1])
if(end[1]-start[1]>(length-gap) and end[1]-start[1]<(length+gap)):
linez.append([start,end])

else:
if(pix[i,j][0]==0 or pix[i,j][1]==255):
start = (i,j)
line = True
return linez

def grouping(hor,width):
"""
Groups similar horizontal lines together.
hor: List of lines in the format [[(start_x,start_y),(end_x,end_y)],...]
width: What width can a line have. Takes all the lines inside this list into a group
Returns: A list of groups. Each group is a list of lines. Each line has the format [(start_x,start_y),(end_x,end_y)]
"""
horSet = set()
for i in hor:
horSet.add((i[0],i[1]))
group =
count = 0
for i in hor:
if (i[0],i[1]) in horSet:
print("Visiting :"+str(i))
for j in hor:
if (j[0],j[1]) in horSet:
if(i[0][0]==j[0][0] and i[1][0]==j[1][0] and abs(j[0][1]-i[0][1])<width and abs(j[1][1]-i[1][1])<width):
if(len(group)<=count):
group.append([j])
else:
group[count].append(j)
horSet.remove((j[0],j[1]))
count+=1
return group
def groupingH(ver,width,heightDifference = 2):
"""
Groups similar vertical lines together.
hor: List of lines in the format [[(start_x,start_y),(end_x,end_y)],...]
width: What width can a line have. Takes all the lines inside this list into a group
Returns: A list of groups. Each group is a list of lines. Each line has the format [(start_x,start_y),(end_x,end_y)]
"""
verSet = set()
for i in ver:
verSet.add((i[0],i[1]))
group =
count = 0
for i in ver:
if (i[0],i[1]) in verSet:
for j in ver:
if (abs(i[0][1]-j[0][1])< heightDifference and abs(i[1][1]-j[1][1])< heightDifference and abs(j[0][0]-i[0][0])<width and abs(j[1][0]-i[1][0])<width):
if(len(group)<=count):
group.append([j])
else:
group[count].append(j)
verSet.remove((j[0],j[1]))
count+=1
return group




def boxing(groupList,boxHeight,gap=5,lw=4):
"""
Given a groupList, it makes a list of coordinates of boxes that have a boxHeight height+-5
"""
boxCoord =
groupSet = set()
for i in range(len(groupList)):
groupSet.add(i)
for i,g in enumerate(groupList):
if i in groupSet:
print("On :"+str(i))
for j,g1 in enumerate(groupList):
if j in groupSet:
print(" Checking :"+str(j))
if(g[0][0][0]==g1[0][0][0] and g[0][1][0]==g1[0][1][0] and abs(g[len(g)-1][0][1]-g1[0][0][1])>=boxHeight-gap and abs(g[len(g)-1][0][1]-g1[0][0][1])<boxHeight+gap):
groupSet.remove(j)
print(" removing :"+str(j))
boxCoord.append((g[0][0][0]+lw,min(g[len(g)-1][0][1],g1[0][0][1])+1,g[0][1][0]-lw,max(g[len(g)-1][0][1],g1[0][0][1])-1))
break
groupSet.remove(i)
return boxCoord

##############################
def getFrontPageBoxes(im,pg,coords,margin=10):
"""
coords[0]: List of lengths of horizontal lines to be recognized: 0th for box1, 1st for box2+3 (and 4,5,6,7,8,9,10)
coords[1]: Height of box 1
coords[2]: Height of box 2,3
coords[3]: Height of box 4,5,6,7
coords[4]: Height of box 8,10
coords[5]: Height of box 9
"""
# Box 1: Police station... et cetera.
t =
t1 = t.append(time())
linez = searchHorizontalLinesX(im,coords[0],0) #0 for box 1 <-- Takes time
t2 = t.append(time())
groupForBox1 = grouping(linez[0],4)
leftUpperCorner = groupForBox1[0][len(groupForBox1[0])-1][0]
t3 = t.append(time())
verLinez = searchVerticalLines(im,coords[1],0,10) # <-- Takes time
t4 = t.append(time())
rightLowerCorner = verLinez[0][1]
box1 = im.crop((leftUpperCorner[0]+margin,leftUpperCorner[1]+margin,linez[0][0][1][0]-margin,rightLowerCorner[1]-margin))
# Box 2+3: Polling station name and address
groupForBox2 = grouping(linez[1],4)
bxesFor2 = boxing(groupForBox2,coords[2])
box2Uncropped = im.crop(bxesFor2[len(bxesFor2)-1]) # The last one is the one we want
t5 = t.append(time())
verLinesFor2 = searchVerticalLines(box2Uncropped,box2Uncropped.size[1],0,10) # <-- Takes time
t6 = t.append(time())
group2ForBox2 = groupingH(verLinesFor2,4)
leftUpperCorner = (0,0)
rightLowerCorner = group2ForBox2[0][0][1]
box2 = box2Uncropped.crop((leftUpperCorner[0]+margin,leftUpperCorner[1]+margin,rightLowerCorner[0]-margin,rightLowerCorner[1]-margin))
# Box 4,5,6,7:
groupForBox4 = groupForBox2
bxesFor4 = boxing(groupForBox4,coords[3])
box4Uncropped = im.crop(bxesFor4[0])
t7 = t.append(time())
verLinesFor4 = searchVerticalLines(box4Uncropped,box4Uncropped.size[1],0,10) # <-- Takes time
t8 = t.append(time())
group2ForBox4 = groupingH(verLinesFor4,4)
#There must be 5 groups.

# Error raising mechanism needed here
maleBox = box4Uncropped.crop((group2ForBox4[1][len(group2ForBox4[1])-1][0][0]+margin,0+margin,group2ForBox4[2][0][0][0]-margin,box4Uncropped.size[1]-margin))
femaleBox = box4Uncropped.crop((group2ForBox4[2][len(group2ForBox4[2])-1][0][0]+margin,0+margin,group2ForBox4[3][0][0][0]-margin,box4Uncropped.size[1]-margin))
third_gender = box4Uncropped.crop((group2ForBox4[3][len(group2ForBox4[3])-1][0][0]+margin,0+margin,group2ForBox4[4][0][0][0]-margin,box4Uncropped.size[1]-margin))
total = box4Uncropped.crop((group2ForBox4[4][len(group2ForBox4[4])-1][0][0]+margin,0+margin,box4Uncropped.size[0]-margin,box4Uncropped.size[1]-margin))

# Box 8, 10:
groupForBox8 = groupForBox2
bxesFor8 = boxing(groupForBox8,coords[4])
box8Uncropped = im.crop(bxesFor8[0])
t9 = t.append(time())
verLinesFor8 = searchVerticalLines(box8Uncropped,box8Uncropped.size[1],0,10) # <--Takes time
t10 = t.append(time())
group2ForBox8 = groupingH(verLinesFor8,4)
box10 = box8Uncropped.crop((group2ForBox8[0][len(group2ForBox8)-1][0][0]+margin,0+margin,box8Uncropped.size[0]-margin,box8Uncropped.size[1]-margin))
box8 = box8Uncropped.crop((0+margin,0+margin,group2ForBox8[0][0][0][0]-margin,box8Uncropped.size[1]-margin))

# Box 9:
groupForBox9 = groupForBox2
bxesFor9= boxing(groupForBox9,coords[5])
box9 = im.crop((bxesFor9[0][0]+margin,bxesFor9[0][1]+margin,bxesFor9[0][2]-margin,bxesFor9[0][3]-margin))
for i in range(0,len(t)-1):
print('Time taken :'+str(t[i+1]-t[i]))
return [box1,box2,maleBox,femaleBox,third_gender,total,box8,box9,box10]
def processBoxes(bxLst):
opList =
for i,box in enumerate(bxLst):
print("box :"+str(i))
opList.append(pt.image_to_string(box,lang='hin+eng',config='--psm 6'))
return opList

def getFrontPageInfo(im,pg,coords):
"""
coords[0]: List of lengths of horizontal lines to be recognized: 0th for box1, 1st for box2+3,
2nd for boxes 4,5,6,7, 3rd for boxes 8 and 10, 4th for box 9
coords[1]: List of lengths of vertical lines to be recognized: 0th for box1
coords[2]: Height of box 2,3
coords[3]: Height of box 4,5,6,7
coords[4]: Height of box 8,10
coords[5]: Height of box 9
"""
boxList = getFrontPageBoxes(im,pg,coords)
return processBoxes(boxList)









share|improve this question
















I have the following image:
enter image description here



from which I want to extract the boxes inside which a triangle is shown. I did it using simple vertical and horizontal line detection, which takes a total of 10 seconds on my machine.



Now, since this has to be done a lot of times, efficiency is of great concern. So, is there any method in openCV (or anywhere else) that can extract these boxes efficiently? Here an efficient method that takes less time than the brute force approach would suffice.



Any help is appreciated!



My approach:



I've made a function searchHorizontalLinesX that is used to search lines of particular lengths. It does so by going through every pixel once. My image has the dimensions: 2479 x 3504 = 8686416 pixels. (The image attached is of low quality, since the upload limit is 2MB. The image I am using is of more than 16 MB)



So, I input the width of the whole box (L1), and the width of box numbered 5(L2). Now, the function returns lines that have L1 length and L2 length. So, all the ones having L1 lengths can be used to extract boxes 1,2,3,4,6,7,8,9 and 10.



Once the lines are found, I search for the lines that have a difference of H between them, where H is the height of each box, for each box. Using these I get the boxes.



For the boxes that aren't the whole column that was extracted then I try to find a line that goes from the top to the bottom and then extract the image on the relevant side of the line.



def searchHorizontalLinesX(im,lengths,pg,gap=10):
"""
im: PIL image object of the file
lengths: list of lengths of lines to recognize
pg: Page number of the page to take under consideration
"""
im.seek(pg)
dimX = im.size[0]
dimY = im.size[1]
pix = im.load()
line = False
n = len(lengths)
linez = [ for i in range(0,n)]
for j in range(0,dimY):
for i in range(0,dimX):
if(line):
if(pix[i,j][0]!=0 or pix[i,j][1]!=255):
line = False
end = (i-1,j)
for num,l in enumerate(lengths):
if(end[0]-start[0]>(l-gap) and end[0]-start[0]<(l+gap)):
linez[num].append([start,end])
elif(start[1]==j-1 and i==0):#End to end line
end = (im.size[0],start[1])
line = False
for i,l in enumerate(lengths):
if(end[0]-start[0]>(l-gap) and end[0]-start[0]<(l+gap)):
linez[num].append([start,end])
else:
if(pix[i,j][0]==0 or pix[i,j][1]==255):
start = (i,j)
line = True
return linez

def searchVerticalLines(im,length,pg,gap=5):
"""
im: PIL image object of the file
length: Length of box
dimX: Width of the page
dimY: Height of the page
pg: Page number of the page to take under consideration
"""
im.seek(pg)
dimX = im.size[0]
dimY = im.size[1]
pix = im.load()
line = False
linez =
start = (0,0)
end = (0,0)
for i in range(0,dimX):
for j in range(0,dimY):
if(line):
if(pix[i,j][0]!=0 or pix[i,j][1]!=255):
line = False
end = (i,j-1)
if(end[1]-start[1]>(length-gap) and end[1]-start[1]<(length+gap)):
linez.append([start,end])
elif(start[0]==i-1 and j==0):
line = False
end = (start[0],im.size[1])
if(end[1]-start[1]>(length-gap) and end[1]-start[1]<(length+gap)):
linez.append([start,end])

else:
if(pix[i,j][0]==0 or pix[i,j][1]==255):
start = (i,j)
line = True
return linez

def grouping(hor,width):
"""
Groups similar horizontal lines together.
hor: List of lines in the format [[(start_x,start_y),(end_x,end_y)],...]
width: What width can a line have. Takes all the lines inside this list into a group
Returns: A list of groups. Each group is a list of lines. Each line has the format [(start_x,start_y),(end_x,end_y)]
"""
horSet = set()
for i in hor:
horSet.add((i[0],i[1]))
group =
count = 0
for i in hor:
if (i[0],i[1]) in horSet:
print("Visiting :"+str(i))
for j in hor:
if (j[0],j[1]) in horSet:
if(i[0][0]==j[0][0] and i[1][0]==j[1][0] and abs(j[0][1]-i[0][1])<width and abs(j[1][1]-i[1][1])<width):
if(len(group)<=count):
group.append([j])
else:
group[count].append(j)
horSet.remove((j[0],j[1]))
count+=1
return group
def groupingH(ver,width,heightDifference = 2):
"""
Groups similar vertical lines together.
hor: List of lines in the format [[(start_x,start_y),(end_x,end_y)],...]
width: What width can a line have. Takes all the lines inside this list into a group
Returns: A list of groups. Each group is a list of lines. Each line has the format [(start_x,start_y),(end_x,end_y)]
"""
verSet = set()
for i in ver:
verSet.add((i[0],i[1]))
group =
count = 0
for i in ver:
if (i[0],i[1]) in verSet:
for j in ver:
if (abs(i[0][1]-j[0][1])< heightDifference and abs(i[1][1]-j[1][1])< heightDifference and abs(j[0][0]-i[0][0])<width and abs(j[1][0]-i[1][0])<width):
if(len(group)<=count):
group.append([j])
else:
group[count].append(j)
verSet.remove((j[0],j[1]))
count+=1
return group




def boxing(groupList,boxHeight,gap=5,lw=4):
"""
Given a groupList, it makes a list of coordinates of boxes that have a boxHeight height+-5
"""
boxCoord =
groupSet = set()
for i in range(len(groupList)):
groupSet.add(i)
for i,g in enumerate(groupList):
if i in groupSet:
print("On :"+str(i))
for j,g1 in enumerate(groupList):
if j in groupSet:
print(" Checking :"+str(j))
if(g[0][0][0]==g1[0][0][0] and g[0][1][0]==g1[0][1][0] and abs(g[len(g)-1][0][1]-g1[0][0][1])>=boxHeight-gap and abs(g[len(g)-1][0][1]-g1[0][0][1])<boxHeight+gap):
groupSet.remove(j)
print(" removing :"+str(j))
boxCoord.append((g[0][0][0]+lw,min(g[len(g)-1][0][1],g1[0][0][1])+1,g[0][1][0]-lw,max(g[len(g)-1][0][1],g1[0][0][1])-1))
break
groupSet.remove(i)
return boxCoord

##############################
def getFrontPageBoxes(im,pg,coords,margin=10):
"""
coords[0]: List of lengths of horizontal lines to be recognized: 0th for box1, 1st for box2+3 (and 4,5,6,7,8,9,10)
coords[1]: Height of box 1
coords[2]: Height of box 2,3
coords[3]: Height of box 4,5,6,7
coords[4]: Height of box 8,10
coords[5]: Height of box 9
"""
# Box 1: Police station... et cetera.
t =
t1 = t.append(time())
linez = searchHorizontalLinesX(im,coords[0],0) #0 for box 1 <-- Takes time
t2 = t.append(time())
groupForBox1 = grouping(linez[0],4)
leftUpperCorner = groupForBox1[0][len(groupForBox1[0])-1][0]
t3 = t.append(time())
verLinez = searchVerticalLines(im,coords[1],0,10) # <-- Takes time
t4 = t.append(time())
rightLowerCorner = verLinez[0][1]
box1 = im.crop((leftUpperCorner[0]+margin,leftUpperCorner[1]+margin,linez[0][0][1][0]-margin,rightLowerCorner[1]-margin))
# Box 2+3: Polling station name and address
groupForBox2 = grouping(linez[1],4)
bxesFor2 = boxing(groupForBox2,coords[2])
box2Uncropped = im.crop(bxesFor2[len(bxesFor2)-1]) # The last one is the one we want
t5 = t.append(time())
verLinesFor2 = searchVerticalLines(box2Uncropped,box2Uncropped.size[1],0,10) # <-- Takes time
t6 = t.append(time())
group2ForBox2 = groupingH(verLinesFor2,4)
leftUpperCorner = (0,0)
rightLowerCorner = group2ForBox2[0][0][1]
box2 = box2Uncropped.crop((leftUpperCorner[0]+margin,leftUpperCorner[1]+margin,rightLowerCorner[0]-margin,rightLowerCorner[1]-margin))
# Box 4,5,6,7:
groupForBox4 = groupForBox2
bxesFor4 = boxing(groupForBox4,coords[3])
box4Uncropped = im.crop(bxesFor4[0])
t7 = t.append(time())
verLinesFor4 = searchVerticalLines(box4Uncropped,box4Uncropped.size[1],0,10) # <-- Takes time
t8 = t.append(time())
group2ForBox4 = groupingH(verLinesFor4,4)
#There must be 5 groups.

# Error raising mechanism needed here
maleBox = box4Uncropped.crop((group2ForBox4[1][len(group2ForBox4[1])-1][0][0]+margin,0+margin,group2ForBox4[2][0][0][0]-margin,box4Uncropped.size[1]-margin))
femaleBox = box4Uncropped.crop((group2ForBox4[2][len(group2ForBox4[2])-1][0][0]+margin,0+margin,group2ForBox4[3][0][0][0]-margin,box4Uncropped.size[1]-margin))
third_gender = box4Uncropped.crop((group2ForBox4[3][len(group2ForBox4[3])-1][0][0]+margin,0+margin,group2ForBox4[4][0][0][0]-margin,box4Uncropped.size[1]-margin))
total = box4Uncropped.crop((group2ForBox4[4][len(group2ForBox4[4])-1][0][0]+margin,0+margin,box4Uncropped.size[0]-margin,box4Uncropped.size[1]-margin))

# Box 8, 10:
groupForBox8 = groupForBox2
bxesFor8 = boxing(groupForBox8,coords[4])
box8Uncropped = im.crop(bxesFor8[0])
t9 = t.append(time())
verLinesFor8 = searchVerticalLines(box8Uncropped,box8Uncropped.size[1],0,10) # <--Takes time
t10 = t.append(time())
group2ForBox8 = groupingH(verLinesFor8,4)
box10 = box8Uncropped.crop((group2ForBox8[0][len(group2ForBox8)-1][0][0]+margin,0+margin,box8Uncropped.size[0]-margin,box8Uncropped.size[1]-margin))
box8 = box8Uncropped.crop((0+margin,0+margin,group2ForBox8[0][0][0][0]-margin,box8Uncropped.size[1]-margin))

# Box 9:
groupForBox9 = groupForBox2
bxesFor9= boxing(groupForBox9,coords[5])
box9 = im.crop((bxesFor9[0][0]+margin,bxesFor9[0][1]+margin,bxesFor9[0][2]-margin,bxesFor9[0][3]-margin))
for i in range(0,len(t)-1):
print('Time taken :'+str(t[i+1]-t[i]))
return [box1,box2,maleBox,femaleBox,third_gender,total,box8,box9,box10]
def processBoxes(bxLst):
opList =
for i,box in enumerate(bxLst):
print("box :"+str(i))
opList.append(pt.image_to_string(box,lang='hin+eng',config='--psm 6'))
return opList

def getFrontPageInfo(im,pg,coords):
"""
coords[0]: List of lengths of horizontal lines to be recognized: 0th for box1, 1st for box2+3,
2nd for boxes 4,5,6,7, 3rd for boxes 8 and 10, 4th for box 9
coords[1]: List of lengths of vertical lines to be recognized: 0th for box1
coords[2]: Height of box 2,3
coords[3]: Height of box 4,5,6,7
coords[4]: Height of box 8,10
coords[5]: Height of box 9
"""
boxList = getFrontPageBoxes(im,pg,coords)
return processBoxes(boxList)






image opencv shapes






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 15 '18 at 17:08







Mooncrater

















asked Nov 15 '18 at 15:50









MooncraterMooncrater

9701131




9701131












  • Unfortunately, 10 seconds on my machine is not enough information to work on optimization problem.

    – Rick M.
    Nov 15 '18 at 16:28











  • @RickM Does the code help?

    – Mooncrater
    Nov 15 '18 at 17:08






  • 1





    Get a faster machine?

    – barny
    Nov 16 '18 at 0:34






  • 3





    I think if you're working with a specific type of document like this and want to get the information in some certain boxes, you should create maskes of where those boxes located in the document, then you only need to detect the document in the image and apply those maskes in.

    – Ha Bom
    Nov 16 '18 at 3:16











  • @HaBom Can you help me find some resources?

    – Mooncrater
    Nov 17 '18 at 3:25

















  • Unfortunately, 10 seconds on my machine is not enough information to work on optimization problem.

    – Rick M.
    Nov 15 '18 at 16:28











  • @RickM Does the code help?

    – Mooncrater
    Nov 15 '18 at 17:08






  • 1





    Get a faster machine?

    – barny
    Nov 16 '18 at 0:34






  • 3





    I think if you're working with a specific type of document like this and want to get the information in some certain boxes, you should create maskes of where those boxes located in the document, then you only need to detect the document in the image and apply those maskes in.

    – Ha Bom
    Nov 16 '18 at 3:16











  • @HaBom Can you help me find some resources?

    – Mooncrater
    Nov 17 '18 at 3:25
















Unfortunately, 10 seconds on my machine is not enough information to work on optimization problem.

– Rick M.
Nov 15 '18 at 16:28





Unfortunately, 10 seconds on my machine is not enough information to work on optimization problem.

– Rick M.
Nov 15 '18 at 16:28













@RickM Does the code help?

– Mooncrater
Nov 15 '18 at 17:08





@RickM Does the code help?

– Mooncrater
Nov 15 '18 at 17:08




1




1





Get a faster machine?

– barny
Nov 16 '18 at 0:34





Get a faster machine?

– barny
Nov 16 '18 at 0:34




3




3





I think if you're working with a specific type of document like this and want to get the information in some certain boxes, you should create maskes of where those boxes located in the document, then you only need to detect the document in the image and apply those maskes in.

– Ha Bom
Nov 16 '18 at 3:16





I think if you're working with a specific type of document like this and want to get the information in some certain boxes, you should create maskes of where those boxes located in the document, then you only need to detect the document in the image and apply those maskes in.

– Ha Bom
Nov 16 '18 at 3:16













@HaBom Can you help me find some resources?

– Mooncrater
Nov 17 '18 at 3:25





@HaBom Can you help me find some resources?

– Mooncrater
Nov 17 '18 at 3:25












1 Answer
1






active

oldest

votes


















1














Look at my code with comment for more details. I just make a sample of only 1 box. Apply the same method to others.



import cv2

img = cv2.imread("1.png")


imgray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray,127,255,0)
cv2.bitwise_not(thresh,thresh)

im2, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

#find the document in the image
max_area = 0
max_contour = None
ind = 0
for i,c in enumerate(contours):
area = cv2.contourArea(c)
if area>max_area:
max_area = area
max_contour = c
ind = i
cv2.drawContours(img, contours, ind ,(0,0,255), 2)

#extract the document
rect = cv2.boundingRect(max_contour)
roi = img[rect[1]:rect[1]+rect[3],rect[0]:rect[0]+rect[2]]

(h,w) = roi.shape[:2]

#create a mask (the mask of box 1)
mask1 = (0,0,w*0.88,h*0.062) #the parameter 0.88 and 0.062 were found base on the format of the document
cv2.rectangle(roi,(mask1[0],mask1[1]),(int(mask1[2]),int(mask1[3])),(0,255,0),2)


cv2.imshow("img",img)
cv2.imshow("ROI",roi)
cv2.waitKey()
cv2.destroyAllWindows()


enter image description here



enter image description here






share|improve this answer























  • Why not find all the contours and choose the ones that are needed? That wouldn't require any cropping and getting the rectangles manually. What do you think?

    – Mooncrater
    Nov 17 '18 at 15:59







  • 1





    The reason is that only some certain boxes are chosen, and you can not make sure the contours you get in different images are in the same order.

    – Ha Bom
    Nov 17 '18 at 16:16











Your Answer






StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













draft saved

draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53323131%2ffinding-particular-boxes-in-an-image-using-opencv%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














Look at my code with comment for more details. I just make a sample of only 1 box. Apply the same method to others.



import cv2

img = cv2.imread("1.png")


imgray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray,127,255,0)
cv2.bitwise_not(thresh,thresh)

im2, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

#find the document in the image
max_area = 0
max_contour = None
ind = 0
for i,c in enumerate(contours):
area = cv2.contourArea(c)
if area>max_area:
max_area = area
max_contour = c
ind = i
cv2.drawContours(img, contours, ind ,(0,0,255), 2)

#extract the document
rect = cv2.boundingRect(max_contour)
roi = img[rect[1]:rect[1]+rect[3],rect[0]:rect[0]+rect[2]]

(h,w) = roi.shape[:2]

#create a mask (the mask of box 1)
mask1 = (0,0,w*0.88,h*0.062) #the parameter 0.88 and 0.062 were found base on the format of the document
cv2.rectangle(roi,(mask1[0],mask1[1]),(int(mask1[2]),int(mask1[3])),(0,255,0),2)


cv2.imshow("img",img)
cv2.imshow("ROI",roi)
cv2.waitKey()
cv2.destroyAllWindows()


enter image description here



enter image description here






share|improve this answer























  • Why not find all the contours and choose the ones that are needed? That wouldn't require any cropping and getting the rectangles manually. What do you think?

    – Mooncrater
    Nov 17 '18 at 15:59







  • 1





    The reason is that only some certain boxes are chosen, and you can not make sure the contours you get in different images are in the same order.

    – Ha Bom
    Nov 17 '18 at 16:16















1














Look at my code with comment for more details. I just make a sample of only 1 box. Apply the same method to others.



import cv2

img = cv2.imread("1.png")


imgray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray,127,255,0)
cv2.bitwise_not(thresh,thresh)

im2, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

#find the document in the image
max_area = 0
max_contour = None
ind = 0
for i,c in enumerate(contours):
area = cv2.contourArea(c)
if area>max_area:
max_area = area
max_contour = c
ind = i
cv2.drawContours(img, contours, ind ,(0,0,255), 2)

#extract the document
rect = cv2.boundingRect(max_contour)
roi = img[rect[1]:rect[1]+rect[3],rect[0]:rect[0]+rect[2]]

(h,w) = roi.shape[:2]

#create a mask (the mask of box 1)
mask1 = (0,0,w*0.88,h*0.062) #the parameter 0.88 and 0.062 were found base on the format of the document
cv2.rectangle(roi,(mask1[0],mask1[1]),(int(mask1[2]),int(mask1[3])),(0,255,0),2)


cv2.imshow("img",img)
cv2.imshow("ROI",roi)
cv2.waitKey()
cv2.destroyAllWindows()


enter image description here



enter image description here






share|improve this answer























  • Why not find all the contours and choose the ones that are needed? That wouldn't require any cropping and getting the rectangles manually. What do you think?

    – Mooncrater
    Nov 17 '18 at 15:59







  • 1





    The reason is that only some certain boxes are chosen, and you can not make sure the contours you get in different images are in the same order.

    – Ha Bom
    Nov 17 '18 at 16:16













1












1








1







Look at my code with comment for more details. I just make a sample of only 1 box. Apply the same method to others.



import cv2

img = cv2.imread("1.png")


imgray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray,127,255,0)
cv2.bitwise_not(thresh,thresh)

im2, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

#find the document in the image
max_area = 0
max_contour = None
ind = 0
for i,c in enumerate(contours):
area = cv2.contourArea(c)
if area>max_area:
max_area = area
max_contour = c
ind = i
cv2.drawContours(img, contours, ind ,(0,0,255), 2)

#extract the document
rect = cv2.boundingRect(max_contour)
roi = img[rect[1]:rect[1]+rect[3],rect[0]:rect[0]+rect[2]]

(h,w) = roi.shape[:2]

#create a mask (the mask of box 1)
mask1 = (0,0,w*0.88,h*0.062) #the parameter 0.88 and 0.062 were found base on the format of the document
cv2.rectangle(roi,(mask1[0],mask1[1]),(int(mask1[2]),int(mask1[3])),(0,255,0),2)


cv2.imshow("img",img)
cv2.imshow("ROI",roi)
cv2.waitKey()
cv2.destroyAllWindows()


enter image description here



enter image description here






share|improve this answer













Look at my code with comment for more details. I just make a sample of only 1 box. Apply the same method to others.



import cv2

img = cv2.imread("1.png")


imgray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray,127,255,0)
cv2.bitwise_not(thresh,thresh)

im2, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

#find the document in the image
max_area = 0
max_contour = None
ind = 0
for i,c in enumerate(contours):
area = cv2.contourArea(c)
if area>max_area:
max_area = area
max_contour = c
ind = i
cv2.drawContours(img, contours, ind ,(0,0,255), 2)

#extract the document
rect = cv2.boundingRect(max_contour)
roi = img[rect[1]:rect[1]+rect[3],rect[0]:rect[0]+rect[2]]

(h,w) = roi.shape[:2]

#create a mask (the mask of box 1)
mask1 = (0,0,w*0.88,h*0.062) #the parameter 0.88 and 0.062 were found base on the format of the document
cv2.rectangle(roi,(mask1[0],mask1[1]),(int(mask1[2]),int(mask1[3])),(0,255,0),2)


cv2.imshow("img",img)
cv2.imshow("ROI",roi)
cv2.waitKey()
cv2.destroyAllWindows()


enter image description here



enter image description here







share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 17 '18 at 5:06









Ha BomHa Bom

1,4562619




1,4562619












  • Why not find all the contours and choose the ones that are needed? That wouldn't require any cropping and getting the rectangles manually. What do you think?

    – Mooncrater
    Nov 17 '18 at 15:59







  • 1





    The reason is that only some certain boxes are chosen, and you can not make sure the contours you get in different images are in the same order.

    – Ha Bom
    Nov 17 '18 at 16:16

















  • Why not find all the contours and choose the ones that are needed? That wouldn't require any cropping and getting the rectangles manually. What do you think?

    – Mooncrater
    Nov 17 '18 at 15:59







  • 1





    The reason is that only some certain boxes are chosen, and you can not make sure the contours you get in different images are in the same order.

    – Ha Bom
    Nov 17 '18 at 16:16
















Why not find all the contours and choose the ones that are needed? That wouldn't require any cropping and getting the rectangles manually. What do you think?

– Mooncrater
Nov 17 '18 at 15:59






Why not find all the contours and choose the ones that are needed? That wouldn't require any cropping and getting the rectangles manually. What do you think?

– Mooncrater
Nov 17 '18 at 15:59





1




1





The reason is that only some certain boxes are chosen, and you can not make sure the contours you get in different images are in the same order.

– Ha Bom
Nov 17 '18 at 16:16





The reason is that only some certain boxes are chosen, and you can not make sure the contours you get in different images are in the same order.

– Ha Bom
Nov 17 '18 at 16:16



















draft saved

draft discarded
















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53323131%2ffinding-particular-boxes-in-an-image-using-opencv%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Darth Vader #20

How to how show current date and time by default on contact form 7 in WordPress without taking input from user in datetimepicker

Ondo