Boost Python update
This looks interesting, I'll have to take a deeper look at it S.P.E.A.D.. A fast protocol for throwing NumPY Arrays about. Berkeley, so you know they're serious. Could be an interesting reference for what I'm doing. And certainly, I want to throw NumPy arrays about!
So I've compiled the 'Hello World' example natively on the Pi...
#include <boost/python.hpp>
namespace bp=boost::python
int test() {
return 42;
}
BOOST_PYTHON_MODULE(smoke_test) {
bp::def( "test", test );
}
Real 0m27.47Ouch, this is a journey back in time. But I can build on it.
Connected Components Update
Python implementation is done and predictably slow, ~0.55 sec for a basic image with 75 blobs on an i7 ~2.6GHz. I'm not sure what the slow set could be, as it's not doing much. Visiting every pixel of an image *is* going to be slow though.
The core implementation is as follows:
class Region( object ):
def __init__( self ):
# Reset does the job
self.reset()
def __str__( self ):
return "x{} n{} r{} a{} ".format( self.last_x, self.last_n, self.last_row, self.area )
def __repr__( self ):
return self.__str__()
def reset( self ):
# zero out settings
# BB
self.bb_x = self.bb_y = 1e6
self.bb_n = self.bb_m = 0
# Line scanning / merging
self.last_row = self.first_row = 0
self.last_x = self.last_n = 0
# Statistics about region
self.area = 0
def updateStats( self, area ):
self.area += area
def combineFrom( self, other ):
self.updateBB( other.bb_x, other.bb_y, other.bb_n, other.bb_m )
self.updateStats( other.area )
# set the linedata explicitly
def setLineData( self, x, n, r ):
self.last_x = x
self.last_n = n
self.last_row = r
def updateBB( self, x, y, n, m ):
self.bb_x = min( self.bb_x, x )
self.bb_y = min( self.bb_y, y )
self.bb_n = max( self.bb_n, n )
self.bb_m = max( self.bb_m, m )
def tidyList( regions, range_idx, row ):
end = len( regions ) - 1
scan_idx = range_idx
while( scan_idx < end ):
if (regions[range_idx].last_row < row ):
range_idx += 1
scan_idx += 1
region_idx = end
while( region_idx > range_idx ):
if( regions[region_idx].last_row < row ):
elem = regions[region_idx]
regions.remove( elem )
regions.insert( range_idx, elem )
range_idx += 1
region_idx -= 1
# end
return range_idx
def connectedComponents( img, threashold ):
rows, cols = len(img), len(img[0]) # assumes row MJR, 1 channel (8-Bit Grey)
# vars used in algo
current_region = 0
region_scan_start = 0
in_line = False
# TODO Replace with 'temp' region
line_start = line_end = area = 0
cidx = -1
region_list = []
for ridx in xrange( rows ):
# do row
current_region = region_scan_start
cidx = 0
in_line = False
line_start = area = 0
line_end = -1
while( cidx < cols ):
px = img[ridx][cidx]
if( px > threashold ):
in_line = True
line_start = cidx
area += 1
else:
cidx += 1
while( in_line ):
cidx += 1
if( cidx < cols ):
if( img[ridx][cidx] < threashold ):
in_line = False
line_end = cidx
else:
area += 1
else:
# run out of data
in_line = False
line_end = cidx
# if line found
if( line_end > line_start ):
# scan regions for merge or insert
regionscanning = True
merge_mode = 0
while( regionscanning ):
if( current_region >= len(region_list) ):
# end of list.
regionscanning = False
if( merge_mode == 0 ):
# the line hasn't merged, so append
newReg = Region()
newReg.setLineData( line_start, line_end, ridx )
newReg.updateBB( line_start, ridx, line_end, ridx )
newReg.updateStats( area )
# insert into list
region_list.append( newReg )
current_region += 1
elif( line_start > region_list[current_region].last_n ):
# skip towards a region
current_region += 1
elif( line_end < region_list[current_region].last_x ):
regionscanning = False
if( merge_mode == 0 ):
# insert new region at current_region, before next
newReg = Region()
newReg.updateBB( line_start, ridx, line_end, ridx )
newReg.updateStats( area )
newReg.setLineData( line_start, line_end, ridx )
# insert into list
region_list.insert( current_region, newReg )
else:
# merging situation
if( merge_mode == 0 ):
# merge line data into region
connectedR = region_list[ current_region ]
connectedR.updateBB( line_start, ridx, line_end, ridx )
connectedR.updateStats( area )
connectedR.setLineData( line_start, line_end, ridx )
merge_mode += 1
current_region += 1 #?
else:
# Multi-Merge
oldReg = region_list[ current_region ]
region_list[ current_region-1 ].combineFrom( oldReg )
region_list.remove( oldReg )
# update with line data
current_region -= 1
if( current_region == region_scan_start ):
regionscanning = False
region_list[ current_region ].setLineData( line_start, line_end, ridx )
# if line_end < last_x
# tidy up
line_start = area = 0
line_end = -1
# ended this row, tidy up region list
region_scan_start = tidyList( region_list, region_scan_start, ridx )
# scanned whole img
return region_list
I could smarten up the 'scanning' section I think, and 'listTidy' keeps rebuilding the list by inserting and dropping elements, so if the job could be done 'in place' that would help. Of course, reimplementing in Threaded, Vectorized C would score some improvements too.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.