@ -22,8 +22,6 @@ mutable Mat_<uchar> dirImage;
int gradThresh ;
int op ;
bool SumFlag ;
int * grads ;
bool PFmode ;
} ;
void ComputeGradientBody : : operator ( ) ( const Range & range ) const
@ -78,9 +76,6 @@ void ComputeGradientBody::operator() (const Range& range) const
gradRow [ x ] = ( ushort ) sum ;
if ( PFmode )
grads [ sum ] + + ;
if ( sum > = gradThresh )
{
if ( gx > = gy )
@ -92,6 +87,9 @@ void ComputeGradientBody::operator() (const Range& range) const
}
}
// Look up table size for fast color space conversion
# define LUT_SIZE (1024*4096)
class EdgeDrawingImpl : public EdgeDrawing
{
public :
@ -126,15 +124,38 @@ protected:
Mat smoothImage ;
uchar * edgeImg ; // pointer to edge image data
uchar * smoothImg ; // pointer to smoothed image data
int segmentNos ;
Mat srcImage ;
int op ; // edge detection operator
int gradThresh ; // gradient threshold
int anchorThresh ; // anchor point threshold
double divForTestSegment ;
double * dH ;
int * grads ;
int np ;
private :
Mat L_Img ;
Mat a_Img ;
Mat b_Img ;
uchar * smooth_L ;
uchar * smooth_a ;
uchar * smooth_b ;
std : : vector < std : : vector < cv : : Point > > segments ;
static double LUT1 [ LUT_SIZE + 1 ] ;
static double LUT2 [ LUT_SIZE + 1 ] ;
static bool LUT_Initialized ;
void MyRGB2LabFast ( ) ;
void ComputeGradientMapByDiZenzo ( ) ;
void smoothChannel ( const Mat & src , Mat & dst , double sigma ) ;
static void fixEdgeSegments ( std : : vector < std : : vector < cv : : Point > > map ) ;
static void InitColorEDLib ( ) ;
void ComputeGradient ( ) ;
void ComputeAnchorPoints ( ) ;
void JoinAnchorPointsUsingSortedAnchors ( ) ;
@ -153,10 +174,7 @@ private:
uchar * dirImg ; // pointer to direction image data
ushort * gradImg ; // pointer to gradient image data
int op ; // edge detection operator
int gradThresh ; // gradient threshold
int anchorThresh ; // anchor point threshold
int segmentNos ;
std : : vector < EDLineSegment > lines ;
int linesNo ;
int min_line_len ;
@ -337,9 +355,9 @@ void EdgeDrawingImpl::write(cv::FileStorage& fs) const
EdgeDrawingImpl : : EdgeDrawingImpl ( )
{
params = EdgeDrawing : : Params ( ) ;
nfa = new NFALUT ( 1 , 1 / 2 , 1 , 1 ) ;
dH = new double [ MAX_GRAD_VALUE ] ;
grads = new int [ MAX_GRAD_VALUE ] ;
nfa = new NFALUT ( 1 , 1 / 8 , 0.5 ) ;
dH = new double [ ED_ MAX_GRAD_VALUE] ;
grads = new int [ ED_ MAX_GRAD_VALUE] ;
}
EdgeDrawingImpl : : ~ EdgeDrawingImpl ( )
@ -351,7 +369,7 @@ EdgeDrawingImpl::~EdgeDrawingImpl()
void EdgeDrawingImpl : : detectEdges ( InputArray src )
{
CV_Assert ( ! src . empty ( ) & & src . type ( ) = = CV_8UC1 ) ;
CV_Assert ( ! src . empty ( ) & & ( src . type ( ) = = CV_8UC1 | | src . type ( ) = = CV_8UC3 | | src . type ( ) = = CV_8UC4 ) ) ;
gradThresh = params . GradientThresholdValue ;
anchorThresh = params . AnchorThresholdValue ;
op = params . EdgeDetectionOperator ;
@ -366,6 +384,9 @@ void EdgeDrawingImpl::detectEdges(InputArray src)
if ( anchorThresh < 0 )
anchorThresh = 0 ;
if ( params . MinPathLength < 3 )
params . MinPathLength = 3 ;
segmentNos = 0 ;
anchorNos = 0 ;
anchorPoints . clear ( ) ;
@ -377,58 +398,157 @@ void EdgeDrawingImpl::detectEdges(InputArray src)
height = srcImage . rows ;
width = srcImage . cols ;
edgeImage = Mat ( height , width , CV_8UC1 , Scalar ( 0 ) ) ; // initialize edge Image
gradImage = Mat ( height , width , CV_16UC1 ) ; // gradImage contains short values
edgeImage = Mat : : zeros ( height , width , CV_8UC1 ) ;
gradImage = Mat : : zeros ( height , width , CV_16UC1 ) ; // gradImage contains short values
dirImage = Mat ( height , width , CV_8UC1 ) ;
if ( params . Sigma < 1.0 )
smoothImage = srcImage ;
else if ( params . Sigma = = 1.0 )
GaussianBlur ( srcImage , smoothImage , Size ( 5 , 5 ) , params . Sigma ) ;
else
GaussianBlur ( srcImage , smoothImage , Size ( ) , params . Sigma ) ; // calculate kernel from sigma
// Assign Pointers from Mat's data
smoothImg = smoothImage . data ;
gradImg = ( ushort * ) gradImage . data ;
edgeImg = edgeImage . data ;
gradImg = ( ushort * ) gradImage . data ;
dirImg = dirImage . data ;
if ( params . PFmode )
if ( srcImage . type ( ) = = CV_8UC1 )
{
memset ( dH , 0 , sizeof ( double ) * MAX_GRAD_VALUE ) ;
memset ( grads , 0 , sizeof ( int ) * MAX_GRAD_VALUE ) ;
}
if ( params . Sigma < 1.0 )
smoothImage = srcImage ;
else if ( params . Sigma = = 1.0 )
GaussianBlur ( srcImage , smoothImage , Size ( 5 , 5 ) , params . Sigma ) ;
else
GaussianBlur ( srcImage , smoothImage , Size ( ) , params . Sigma ) ; // calculate kernel from sigma
smoothImg = smoothImage . data ;
ComputeGradient ( ) ; // COMPUTE GRADIENT & EDGE DIRECTION MAPS
ComputeAnchorPoints ( ) ; // COMPUTE ANCHORS
JoinAnchorPointsUsingSortedAnchors ( ) ; // JOIN ANCHORS
if ( params . PFmode )
{
memset ( gradImg , 0 , sizeof ( short ) * width * height ) ;
memset ( grads , 0 , sizeof ( int ) * ED_MAX_GRAD_VALUE ) ;
memset ( dH , 0 , sizeof ( double ) * ED_MAX_GRAD_VALUE ) ;
memset ( edgeImg , 0 , width * height ) ; // clear edge image
ComputeGradient ( ) ; // COMPUTE GRADIENT & EDGE DIRECTION MAPS
ComputeAnchorPoints ( ) ; // COMPUTE ANCHORS
JoinAnchorPointsUsingSortedAnchors ( ) ; // JOIN ANCHORS
GaussianBlur ( srcImage , smoothImage , Size ( ) , 0.4 ) ;
if ( params . PFmode )
for ( int i = 1 ; i < height - 1 ; i + + ) {
for ( int j = 1 ; j < width - 1 ; j + + ) {
int com1 = smoothImg [ ( i + 1 ) * width + j + 1 ] - smoothImg [ ( i - 1 ) * width + j - 1 ] ;
int com2 = smoothImg [ ( i - 1 ) * width + j + 1 ] - smoothImg [ ( i + 1 ) * width + j - 1 ] ;
int gx = abs ( com1 + com2 + ( smoothImg [ i * width + j + 1 ] - smoothImg [ i * width + j - 1 ] ) ) ;
int gy = abs ( com1 - com2 + ( smoothImg [ ( i + 1 ) * width + j ] - smoothImg [ ( i - 1 ) * width + j ] ) ) ;
int g = gx + gy ;
gradImg [ i * width + j ] = ( ushort ) g ;
grads [ g ] + + ;
}
}
// Compute probability function H
int size = ( width - 2 ) * ( height - 2 ) ;
for ( int i = ED_MAX_GRAD_VALUE - 1 ; i > 0 ; i - - )
grads [ i - 1 ] + = grads [ i ] ;
for ( int i = 0 ; i < ED_MAX_GRAD_VALUE ; i + + )
dH [ i ] = ( double ) grads [ i ] / ( ( double ) size ) ;
divForTestSegment = 2.25 ; // Some magic number :-)
np = 0 ;
for ( int i = 0 ; i < segmentNos ; i + + )
{
int len = ( int ) segmentPoints [ i ] . size ( ) ;
np + = ( len * ( len - 1 ) ) / 2 ;
}
// Validate segments
for ( int i = 0 ; i < segmentNos ; i + + )
TestSegment ( i , 0 , ( int ) segmentPoints [ i ] . size ( ) - 1 ) ;
ExtractNewSegments ( ) ;
}
}
else
{
// Compute probability function H
int size = ( width - 2 ) * ( height - 2 ) ;
// Convert RGB2Lab
MyRGB2LabFast ( ) ;
// Smooth Channels
smoothChannel ( L_Img , L_Img , params . Sigma ) ;
smoothChannel ( a_Img , a_Img , params . Sigma ) ;
smoothChannel ( b_Img , b_Img , params . Sigma ) ;
smooth_L = L_Img . data ;
smooth_a = a_Img . data ;
smooth_b = b_Img . data ;
ComputeGradientMapByDiZenzo ( ) ; // Compute Gradient & Edge Direction Maps
// Compute anchors with the user supplied parameters
anchorThresh = 0 ; // anchorThresh used as zero while computing anchor points if selectStableAnchors set.
// Finding higher number of anchors is OK, because we have following validation steps in selectStableAnchors.
ComputeAnchorPoints ( ) ; // COMPUTE ANCHORS
anchorThresh = params . AnchorThresholdValue ; // set it to its initial argument value for further anchor validation.
anchorPoints . clear ( ) ; // considering validation step below, it should constructed again.
for ( int i = 1 ; i < height - 1 ; i + + ) {
for ( int j = 1 ; j < width - 1 ; j + + ) {
if ( edgeImg [ i * width + j ] ! = ANCHOR_PIXEL ) continue ;
// Take only "stable" anchors
// 0 degree edge
if ( edgeImg [ i * width + j - 1 ] & & edgeImg [ i * width + j + 1 ] ) {
int diff1 = gradImg [ i * width + j ] - gradImg [ ( i - 1 ) * width + j ] ;
int diff2 = gradImg [ i * width + j ] - gradImg [ ( i + 1 ) * width + j ] ;
if ( diff1 > = anchorThresh & & diff2 > = anchorThresh ) edgeImg [ i * width + j ] = 255 ;
for ( int i = MAX_GRAD_VALUE - 1 ; i > 0 ; i - - )
grads [ i - 1 ] + = grads [ i ] ;
continue ;
}
for ( int i = 0 ; i < MAX_GRAD_VALUE ; i + + )
dH [ i ] = ( double ) grads [ i ] / ( ( double ) size ) ;
// 90 degree edge
if ( edgeImg [ ( i - 1 ) * width + j ] & & edgeImg [ ( i + 1 ) * width + j ] ) {
int diff1 = gradImg [ i * width + j ] - gradImg [ i * width + j - 1 ] ;
int diff2 = gradImg [ i * width + j ] - gradImg [ i * width + j + 1 ] ;
if ( diff1 > = anchorThresh & & diff2 > = anchorThresh ) edgeImg [ i * width + j ] = 255 ;
divForTestSegment = 2.25 ; // Some magic number :-)
memset ( edgeImg , 0 , width * height ) ; // clear edge image
np = 0 ;
for ( int i = 0 ; i < segmentNos ; i + + )
{
int len = ( int ) segmentPoints [ i ] . size ( ) ;
np + = ( len * ( len - 1 ) ) / 2 ;
continue ;
}
// 135 degree diagonal
if ( edgeImg [ ( i - 1 ) * width + j - 1 ] & & edgeImg [ ( i + 1 ) * width + j + 1 ] ) {
int diff1 = gradImg [ i * width + j ] - gradImg [ ( i - 1 ) * width + j + 1 ] ;
int diff2 = gradImg [ i * width + j ] - gradImg [ ( i + 1 ) * width + j - 1 ] ;
if ( diff1 > = anchorThresh & & diff2 > = anchorThresh ) edgeImg [ i * width + j ] = 255 ;
continue ;
}
// 45 degree diagonal
if ( edgeImg [ ( i - 1 ) * width + j + 1 ] & & edgeImg [ ( i + 1 ) * width + j - 1 ] ) {
int diff1 = gradImg [ i * width + j ] - gradImg [ ( i - 1 ) * width + j - 1 ] ;
int diff2 = gradImg [ i * width + j ] - gradImg [ ( i + 1 ) * width + j + 1 ] ;
if ( diff1 > = anchorThresh & & diff2 > = anchorThresh ) edgeImg [ i * width + j ] = 255 ;
}
}
}
// Validate segments
for ( int i = 0 ; i < segmentNos ; i + + )
TestSegment ( i , 0 , ( int ) segmentPoints [ i ] . size ( ) - 1 ) ;
for ( int i = 0 ; i < width * height ; i + + )
if ( edgeImg [ i ] = = ANCHOR_PIXEL )
edgeImg [ i ] = 0 ;
else if ( edgeImg [ i ] = = 255 ) {
edgeImg [ i ] = ANCHOR_PIXEL ;
int y = i / width ;
int x = i % width ;
anchorPoints . push_back ( Point ( x , y ) ) ; // push validated anchor point to vector
}
anchorNos = ( int ) anchorPoints . size ( ) ; // get # of anchor pixels
JoinAnchorPointsUsingSortedAnchors ( ) ; // JOIN ANCHORS
ExtractNewSegments ( ) ;
// Fix 1 pixel errors in the edge map
fixEdgeSegments ( segments ) ;
}
}
@ -473,8 +593,6 @@ void EdgeDrawingImpl::ComputeGradient()
body . gradThresh = gradThresh ;
body . SumFlag = params . SumFlag ;
body . op = op ;
body . grads = grads ;
body . PFmode = params . PFmode ;
parallel_for_ ( Range ( 1 , smoothImage . rows - 1 ) , body ) ;
}
@ -562,24 +680,24 @@ void EdgeDrawingImpl::JoinAnchorPointsUsingSortedAnchors()
{
stack [ + + top ] . r = i ;
stack [ top ] . c = j ;
stack [ top ] . dir = DOWN ;
stack [ top ] . dir = ED_ DOWN;
stack [ top ] . parent = 0 ;
stack [ + + top ] . r = i ;
stack [ top ] . c = j ;
stack [ top ] . dir = UP ;
stack [ top ] . dir = ED_ UP;
stack [ top ] . parent = 0 ;
}
else
{
stack [ + + top ] . r = i ;
stack [ top ] . c = j ;
stack [ top ] . dir = RIGHT ;
stack [ top ] . dir = ED_ RIGHT;
stack [ top ] . parent = 0 ;
stack [ + + top ] . r = i ;
stack [ top ] . c = j ;
stack [ top ] . dir = LEFT ;
stack [ top ] . dir = ED_ LEFT;
stack [ top ] . parent = 0 ;
}
@ -609,7 +727,7 @@ StartOfWhile:
len + + ;
chainLen + + ;
if ( dir = = LEFT )
if ( dir = = ED_ LEFT)
{
while ( dirImg [ r * width + c ] = = EDGE_HORIZONTAL )
{
@ -680,12 +798,12 @@ StartOfWhile:
stack [ + + top ] . r = r ;
stack [ top ] . c = c ;
stack [ top ] . dir = DOWN ;
stack [ top ] . dir = ED_ DOWN;
stack [ top ] . parent = noChains ;
stack [ + + top ] . r = r ;
stack [ top ] . c = c ;
stack [ top ] . dir = UP ;
stack [ top ] . dir = ED_ UP;
stack [ top ] . parent = noChains ;
len - - ;
@ -695,7 +813,7 @@ StartOfWhile:
chains [ parent ] . children [ 0 ] = noChains ;
noChains + + ;
}
else if ( dir = = RIGHT )
else if ( dir = = ED_ RIGHT)
{
while ( dirImg [ r * width + c ] = = EDGE_HORIZONTAL )
{
@ -766,12 +884,12 @@ StartOfWhile:
stack [ + + top ] . r = r ;
stack [ top ] . c = c ;
stack [ top ] . dir = DOWN ; // Go down
stack [ top ] . dir = ED_ DOWN; // Go down
stack [ top ] . parent = noChains ;
stack [ + + top ] . r = r ;
stack [ top ] . c = c ;
stack [ top ] . dir = UP ; // Go up
stack [ top ] . dir = ED_ UP; // Go up
stack [ top ] . parent = noChains ;
len - - ;
@ -782,7 +900,7 @@ StartOfWhile:
noChains + + ;
}
else if ( dir = = UP )
else if ( dir = = ED_ UP)
{
while ( dirImg [ r * width + c ] = = EDGE_VERTICAL )
{
@ -853,12 +971,12 @@ StartOfWhile:
stack [ + + top ] . r = r ;
stack [ top ] . c = c ;
stack [ top ] . dir = RIGHT ;
stack [ top ] . dir = ED_ RIGHT;
stack [ top ] . parent = noChains ;
stack [ + + top ] . r = r ;
stack [ top ] . c = c ;
stack [ top ] . dir = LEFT ;
stack [ top ] . dir = ED_ LEFT;
stack [ top ] . parent = noChains ;
len - - ;
@ -939,12 +1057,12 @@ StartOfWhile:
stack [ + + top ] . r = r ;
stack [ top ] . c = c ;
stack [ top ] . dir = RIGHT ;
stack [ top ] . dir = ED_ RIGHT;
stack [ top ] . parent = noChains ;
stack [ + + top ] . r = r ;
stack [ top ] . c = c ;
stack [ top ] . dir = LEFT ;
stack [ top ] . dir = ED_ LEFT;
stack [ top ] . parent = noChains ;
len - - ;
@ -1187,17 +1305,13 @@ StartOfWhile:
delete [ ] pixels ;
}
int * EdgeDrawingImpl : : sortAnchorsByGradValue1 ( )
{
int SIZE = 128 * 256 ;
int * C = new int [ SIZE ] ;
memset ( C , 0 , sizeof ( int ) * SIZE ) ;
int * EdgeDrawingImpl : : sortAnchorsByGradValue1 ( ) {
const int SIZE = 128 * 256 ;
std : : vector < int > C ( SIZE , 0 ) ;
// Count the number of grad values
for ( int i = 1 ; i < height - 1 ; i + + )
{
for ( int j = 1 ; j < width - 1 ; j + + )
{
for ( int i = 1 ; i < height - 1 ; i + + ) {
for ( int j = 1 ; j < width - 1 ; j + + ) {
if ( edgeImg [ i * width + j ] ! = ANCHOR_PIXEL )
continue ;
@ -1207,16 +1321,15 @@ int* EdgeDrawingImpl::sortAnchorsByGradValue1()
}
// Compute indices
for ( int i = 1 ; i < SIZE ; i + + )
for ( int i = 1 ; i < SIZE ; i + + ) {
C [ i ] + = C [ i - 1 ] ;
}
int noAnchors = C [ SIZE - 1 ] ;
int * A = new int [ noAnchors ] ;
for ( int i = 1 ; i < height - 1 ; i + + )
{
for ( int j = 1 ; j < width - 1 ; j + + )
{
for ( int i = 1 ; i < height - 1 ; i + + ) {
for ( int j = 1 ; j < width - 1 ; j + + ) {
if ( edgeImg [ i * width + j ] ! = ANCHOR_PIXEL )
continue ;
@ -1226,52 +1339,35 @@ int* EdgeDrawingImpl::sortAnchorsByGradValue1()
}
}
delete [ ] C ;
return A ;
}
int EdgeDrawingImpl : : LongestChain ( Chain * chains , int root )
{
if ( root = = - 1 | | chains [ root ] . len = = 0 )
int EdgeDrawingImpl : : LongestChain ( Chain * chains , int root ) {
if ( root = = - 1 | | chains [ root ] . len = = 0 ) {
return 0 ;
}
int len0 = 0 ;
if ( chains [ root ] . children [ 0 ] ! = - 1 )
len0 = LongestChain ( chains , chains [ root ] . children [ 0 ] ) ;
int len1 = 0 ;
if ( chains [ root ] . children [ 1 ] ! = - 1 )
len1 = LongestChain ( chains , chains [ root ] . children [ 1 ] ) ;
int max = 0 ;
int leftLength = LongestChain ( chains , chains [ root ] . children [ 0 ] ) ;
int rightLength = LongestChain ( chains , chains [ root ] . children [ 1 ] ) ;
if ( len0 > = len1 )
{
max = len0 ;
chains [ root ] . children [ 1 ] = - 1 ;
if ( leftLength > = rightLength ) {
chains [ root ] . children [ 1 ] = - 1 ; // Invalidate the right child
return chains [ root ] . len + leftLength ;
}
else
{
max = len1 ;
chains [ root ] . children [ 0 ] = - 1 ;
else {
chains [ root ] . children [ 0 ] = - 1 ; // Invalidate the left child
return chains [ root ] . len + rightLength ;
}
return chains [ root ] . len + max ;
}
int EdgeDrawingImpl : : RetrieveChainNos ( Chain * chains , int root , int chainNos [ ] )
{
int EdgeDrawingImpl : : RetrieveChainNos ( Chain * chains , int root , int chainNos [ ] ) {
int count = 0 ;
while ( root ! = - 1 )
{
chainNos [ count ] = root ;
count + + ;
while ( root ! = - 1 ) {
chainNos [ count + + ] = root ;
if ( chains [ root ] . children [ 0 ] ! = - 1 )
root = chains [ root ] . children [ 0 ] ;
else
root = chains [ root ] . children [ 1 ] ;
// Move to the next child in the chain
root = ( chains [ root ] . children [ 0 ] ! = - 1 ) ? chains [ root ] . children [ 0 ] : chains [ root ] . children [ 1 ] ;
}
return count ;
@ -1291,7 +1387,7 @@ void EdgeDrawingImpl::detectLines(OutputArray _lines)
max_distance_between_two_lines = params . MaxDistanceBetweenTwoLines ;
max_error = params . MaxErrorThreshold ;
if ( min_line_len = = - 1 ) // If no initial value given, compute it
if ( min_line_len < 0 ) // If no initial value given, compute it
min_line_len = ComputeMinLineLength ( ) ;
if ( min_line_len < 9 ) // avoids small line segments in the result. Might be deleted!
@ -1318,7 +1414,7 @@ void EdgeDrawingImpl::detectLines(OutputArray _lines)
JoinCollinearLines ( ) ;
if ( params . NFAValidation )
if ( params . NFAValidation & & srcImage . channels ( ) < 3 )
ValidateLineSegments ( ) ;
// Delete redundant space from lines
@ -1440,7 +1536,7 @@ void EdgeDrawingImpl::SplitSegment2Lines(double* x, double* y, int noPixels, int
index - - ;
ComputeClosestPoint ( x [ index ] , y [ index ] , lastA , lastB , lastInvert , ex , ey ) ;
if ( ( sx = = ex ) & ( sy = = ey ) )
if ( ( sx = = ex ) & & ( sy = = ey ) )
break ;
// Add the line segment to lines
@ -1517,7 +1613,8 @@ void EdgeDrawingImpl::ValidateLineSegments()
{
int lutSize = ( width + height ) / 8 ;
double prob = 1.0 / 8 ; // probability of alignment
nfa = new NFALUT ( lutSize , prob , width , height ) ;
double logNT = 2.0 * ( log10 ( ( double ) width ) + log10 ( ( double ) height ) ) ;
nfa = new NFALUT ( lutSize , prob , logNT ) ;
}
int * x = new int [ ( width + height ) * 4 ] ;
@ -2037,7 +2134,7 @@ double EdgeDrawingImpl::ComputeMinDistanceBetweenTwoLines(EDLineSegment* ls1, ED
double dy = ls1 - > sy - ls2 - > sy ;
double d = sqrt ( dx * dx + dy * dy ) ;
double min = d ;
int which = SOUTH_SOUTH ;
int which = ED_ SOUTH_SOUTH;
dx = ls1 - > sx - ls2 - > ex ;
dy = ls1 - > sy - ls2 - > ey ;
@ -2045,7 +2142,7 @@ double EdgeDrawingImpl::ComputeMinDistanceBetweenTwoLines(EDLineSegment* ls1, ED
if ( d < min )
{
min = d ;
which = SOUTH_EAST ;
which = ED_ SOUTH_EAST;
}
dx = ls1 - > ex - ls2 - > sx ;
@ -2054,7 +2151,7 @@ double EdgeDrawingImpl::ComputeMinDistanceBetweenTwoLines(EDLineSegment* ls1, ED
if ( d < min )
{
min = d ;
which = EAST_SOUTH ;
which = ED_E AST_SOUTH ;
}
dx = ls1 - > ex - ls2 - > ex ;
@ -2063,7 +2160,7 @@ double EdgeDrawingImpl::ComputeMinDistanceBetweenTwoLines(EDLineSegment* ls1, ED
if ( d < min )
{
min = d ;
which = EAST_EAST ;
which = ED_E AST_EAST ;
}
if ( pwhich )
@ -2370,51 +2467,53 @@ void EdgeDrawingImpl::TestSegment(int i, int index1, int index2)
TestSegment ( i , start , index2 ) ;
}
//----------------------------------------------------------------------------------------------
// After the validation of the edge segments, extracts the valid ones
// In other words, updates the valid segments' pixel arrays and their lengths
// After validating the edge segments, this function extracts the valid ones.
// Specifically, it updates the valid segments' pixel arrays and their lengths based on validation.
void EdgeDrawingImpl : : ExtractNewSegments ( )
{
vector < vector < Point > > validSegments ;
int noSegments = 0 ;
for ( int i = 0 ; i < segmentNos ; i + + ) {
int start = 0 ;
while ( start < ( int ) segmentPoints [ i ] . size ( ) ) {
// Find the first valid start point
while ( start < ( int ) segmentPoints [ i ] . size ( ) ) {
int r = segmentPoints [ i ] [ start ] . y ;
int c = segmentPoints [ i ] [ start ] . x ;
if ( edgeImg [ r * width + c ] ) break ;
if ( edgeImg [ r * width + c ] ) break ; // Found valid point
start + + ;
}
int end = start + 1 ;
// Find the end of the valid segment
while ( end < ( int ) segmentPoints [ i ] . size ( ) ) {
int r = segmentPoints [ i ] [ end ] . y ;
int c = segmentPoints [ i ] [ end ] . x ;
if ( edgeImg [ r * width + c ] = = 0 ) break ;
if ( edgeImg [ r * width + c ] = = 0 ) break ; // End of segment
end + + ;
}
// Length of the segment
int len = end - start ;
// Only accept segments of length >= 10
if ( len > = 10 ) {
// A new segment. Accepted only only long enough (whatever that means)
//segments[noSegments].pixels = &map->segments[i].pixels[start];
//segments[noSegments].noPixels = len;
validSegments . push_back ( vector < Point > ( ) ) ;
vector < Point > subVec ( & segmentPoints [ i ] [ start ] , & segmentPoints [ i ] [ end - 1 ] ) ;
validSegments [ noSegments ] = subVec ;
noSegments + + ;
vector < Point > subVec ( segmentPoints [ i ] . begin ( ) + start , segmentPoints [ i ] . begin ( ) + end ) ; // Safer bounds
validSegments . push_back ( subVec ) ; // Add to valid segments
}
// Move start to next unprocessed point
start = end + 1 ;
}
}
// Replace the old segments with valid segments
segmentPoints = validSegments ;
segmentNos = noSegments ;
segmentNos = ( int ) validSegments . size ( ) ; // Update number of segments
}
double EdgeDrawingImpl : : NFA ( double prob , int len )
@ -3119,7 +3218,8 @@ void EdgeDrawingImpl::ValidateCircles(bool validate)
{
int lutSize = ( width + height ) / 8 ;
double prob = 1.0 / 8 ; // probability of alignment
nfa = new NFALUT ( lutSize , prob , width , height ) ; // create look up table
double logNT = 2.0 * ( log10 ( ( double ) width ) + log10 ( ( double ) height ) ) ;
nfa = new NFALUT ( lutSize , prob , logNT ) ; // create look up table
}
// Validate circles & ellipses
@ -3297,12 +3397,24 @@ void EdgeDrawingImpl::ValidateCircles(bool validate)
// This produces less false positives, but occationally misses on some valid circles
}
out :
// compute gx & gy
int com1 = smoothImg [ ( r + 1 ) * width + c + 1 ] - smoothImg [ ( r - 1 ) * width + c - 1 ] ;
int com2 = smoothImg [ ( r - 1 ) * width + c + 1 ] - smoothImg [ ( r + 1 ) * width + c - 1 ] ;
int com1 , com2 , gx , gy ;
if ( srcImage . channels ( ) > 1 )
{
com1 = smooth_L [ ( r + 1 ) * width + c + 1 ] - smooth_L [ ( r - 1 ) * width + c - 1 ] ;
com2 = smooth_L [ ( r - 1 ) * width + c + 1 ] - smooth_L [ ( r + 1 ) * width + c - 1 ] ;
gx = com1 + com2 + smooth_L [ r * width + c + 1 ] - smooth_L [ r * width + c - 1 ] ;
gy = com1 - com2 + smooth_L [ ( r + 1 ) * width + c ] - smooth_L [ ( r - 1 ) * width + c ] ;
}
else
{
com1 = smoothImg [ ( r + 1 ) * width + c + 1 ] - smoothImg [ ( r - 1 ) * width + c - 1 ] ;
com2 = smoothImg [ ( r - 1 ) * width + c + 1 ] - smoothImg [ ( r + 1 ) * width + c - 1 ] ;
gx = com1 + com2 + smoothImg [ r * width + c + 1 ] - smoothImg [ r * width + c - 1 ] ;
gy = com1 - com2 + smoothImg [ ( r + 1 ) * width + c ] - smoothImg [ ( r - 1 ) * width + c ] ;
}
int gx = com1 + com2 + smoothImg [ r * width + c + 1 ] - smoothImg [ r * width + c - 1 ] ;
int gy = com1 - com2 + smoothImg [ ( r + 1 ) * width + c ] - smoothImg [ ( r - 1 ) * width + c ] ;
double pixelAngle = nfa - > myAtan2 ( ( double ) gx , ( double ) - gy ) ;
double derivX , derivY ;
@ -3778,7 +3890,7 @@ void EdgeDrawingImpl::JoinArcs1()
EX = arcs [ CandidateArcNo ] . sx ;
EY = arcs [ CandidateArcNo ] . sy ;
break ;
} //end-switch
}
break ; // Do not look at the other candidates
}
@ -5745,5 +5857,276 @@ void EdgeDrawingImpl::ROTATE(double** a, int i, int j, int k, int l, double tau,
a [ k ] [ l ] = h + s * ( g - h * tau ) ;
}
void EdgeDrawingImpl : : MyRGB2LabFast ( )
{
const uchar * blueImg ;
const uchar * greenImg ;
const uchar * redImg ;
// Split channels (OpenCV uses BGR)
vector < Mat > bgr ( 3 ) ;
split ( srcImage , bgr ) ;
blueImg = bgr [ 0 ] . data ;
greenImg = bgr [ 1 ] . data ;
redImg = bgr [ 2 ] . data ;
// Initialize LUTs if necessary
if ( ! LUT_Initialized )
InitColorEDLib ( ) ;
L_Img . create ( height , width , CV_8U ) ;
a_Img . create ( height , width , CV_8U ) ;
b_Img . create ( height , width , CV_8U ) ;
std : : vector < double > L ( width * height ) ;
std : : vector < double > a ( width * height ) ;
std : : vector < double > b ( width * height ) ;
// Conversion from RGB to Lab
for ( int i = 0 ; i < width * height ; i + + )
{
double red = LUT1 [ static_cast < int > ( redImg [ i ] / 255.0 * LUT_SIZE + 0.5 ) ] * 100 ;
double green = LUT1 [ static_cast < int > ( greenImg [ i ] / 255.0 * LUT_SIZE + 0.5 ) ] * 100 ;
double blue = LUT1 [ static_cast < int > ( blueImg [ i ] / 255.0 * LUT_SIZE + 0.5 ) ] * 100 ;
double x = red * 0.4124564 + green * 0.3575761 + blue * 0.1804375 ;
double y = red * 0.2126729 + green * 0.7151522 + blue * 0.0721750 ;
double z = red * 0.0193339 + green * 0.1191920 + blue * 0.9503041 ;
x / = 95.047 ;
y / = 100.0 ;
z / = 108.883 ;
x = LUT2 [ static_cast < int > ( x * LUT_SIZE + 0.5 ) ] ;
y = LUT2 [ static_cast < int > ( y * LUT_SIZE + 0.5 ) ] ;
z = LUT2 [ static_cast < int > ( z * LUT_SIZE + 0.5 ) ] ;
L [ i ] = ( 116.0 * y ) - 16 ;
a [ i ] = 500.0 * ( x / y ) ;
b [ i ] = 200.0 * ( y - z ) ;
}
// Scaling to [0, 255]
auto scale_to_uchar = [ ] ( std : : vector < double > & src , uchar * dst , int size ) {
double minVal = * std : : min_element ( src . begin ( ) , src . end ( ) ) ;
double maxVal = * std : : max_element ( src . begin ( ) , src . end ( ) ) ;
double scale = 255.0 / ( maxVal - minVal ) ;
for ( int i = 0 ; i < size ; i + + ) {
dst [ i ] = static_cast < uchar > ( ( src [ i ] - minVal ) * scale ) ;
}
} ;
scale_to_uchar ( L , L_Img . data , width * height ) ;
scale_to_uchar ( a , a_Img . data , width * height ) ;
scale_to_uchar ( b , b_Img . data , width * height ) ;
}
void EdgeDrawingImpl : : ComputeGradientMapByDiZenzo ( )
{
int max = 0 ;
for ( int i = 1 ; i < height - 1 ; i + + ) {
for ( int j = 1 ; j < width - 1 ; j + + ) {
int com1 , com2 , gxCh1 , gxCh2 , gxCh3 , gyCh1 , gyCh2 , gyCh3 ;
if ( params . EdgeDetectionOperator = = PREWITT )
{
// Prewitt for channel1
com1 = smooth_L [ ( i + 1 ) * width + j + 1 ] - smooth_L [ ( i - 1 ) * width + j - 1 ] ;
com2 = smooth_L [ ( i - 1 ) * width + j + 1 ] - smooth_L [ ( i + 1 ) * width + j - 1 ] ;
gxCh1 = com1 + com2 + ( smooth_L [ i * width + j + 1 ] - smooth_L [ i * width + j - 1 ] ) ;
gyCh1 = com1 - com2 + ( smooth_L [ ( i + 1 ) * width + j ] - smooth_L [ ( i - 1 ) * width + j ] ) ;
// Prewitt for channel2
com1 = smooth_a [ ( i + 1 ) * width + j + 1 ] - smooth_a [ ( i - 1 ) * width + j - 1 ] ;
com2 = smooth_a [ ( i - 1 ) * width + j + 1 ] - smooth_a [ ( i + 1 ) * width + j - 1 ] ;
gxCh2 = com1 + com2 + ( smooth_a [ i * width + j + 1 ] - smooth_a [ i * width + j - 1 ] ) ;
gyCh2 = com1 - com2 + ( smooth_a [ ( i + 1 ) * width + j ] - smooth_a [ ( i - 1 ) * width + j ] ) ;
// Prewitt for channel3
com1 = smooth_b [ ( i + 1 ) * width + j + 1 ] - smooth_b [ ( i - 1 ) * width + j - 1 ] ;
com2 = smooth_b [ ( i - 1 ) * width + j + 1 ] - smooth_b [ ( i + 1 ) * width + j - 1 ] ;
gxCh3 = com1 + com2 + ( smooth_b [ i * width + j + 1 ] - smooth_b [ i * width + j - 1 ] ) ;
gyCh3 = com1 - com2 + ( smooth_b [ ( i + 1 ) * width + j ] - smooth_b [ ( i - 1 ) * width + j ] ) ;
}
else
{
// Sobel for channel1
com1 = smooth_L [ ( i + 1 ) * width + j + 1 ] - smooth_L [ ( i - 1 ) * width + j - 1 ] ;
com2 = smooth_L [ ( i - 1 ) * width + j + 1 ] - smooth_L [ ( i + 1 ) * width + j - 1 ] ;
gxCh1 = com1 + com2 + 2 * ( smooth_L [ i * width + j + 1 ] - smooth_L [ i * width + j - 1 ] ) ;
gyCh1 = com1 - com2 + 2 * ( smooth_L [ ( i + 1 ) * width + j ] - smooth_L [ ( i - 1 ) * width + j ] ) ;
// Sobel for channel2
com1 = smooth_a [ ( i + 1 ) * width + j + 1 ] - smooth_a [ ( i - 1 ) * width + j - 1 ] ;
com2 = smooth_a [ ( i - 1 ) * width + j + 1 ] - smooth_a [ ( i + 1 ) * width + j - 1 ] ;
gxCh2 = com1 + com2 + 2 * ( smooth_a [ i * width + j + 1 ] - smooth_a [ i * width + j - 1 ] ) ;
gyCh2 = com1 - com2 + 2 * ( smooth_a [ ( i + 1 ) * width + j ] - smooth_a [ ( i - 1 ) * width + j ] ) ;
// Sobel for channel3
com1 = smooth_b [ ( i + 1 ) * width + j + 1 ] - smooth_b [ ( i - 1 ) * width + j - 1 ] ;
com2 = smooth_b [ ( i - 1 ) * width + j + 1 ] - smooth_b [ ( i + 1 ) * width + j - 1 ] ;
gxCh3 = com1 + com2 + 2 * ( smooth_b [ i * width + j + 1 ] - smooth_b [ i * width + j - 1 ] ) ;
gyCh3 = com1 - com2 + 2 * ( smooth_b [ ( i + 1 ) * width + j ] - smooth_b [ ( i - 1 ) * width + j ] ) ;
}
int gxx = gxCh1 * gxCh1 + gxCh2 * gxCh2 + gxCh3 * gxCh3 ;
int gyy = gyCh1 * gyCh1 + gyCh2 * gyCh2 + gyCh3 * gyCh3 ;
int gxy = gxCh1 * gyCh1 + gxCh2 * gyCh2 + gxCh3 * gyCh3 ;
# if 1
// Di Zenzo's formulas from Gonzales & Woods - Page 337
double theta = atan2 ( 2.0 * gxy , ( double ) ( gxx - gyy ) ) / 2 ; // Gradient Direction
int grad = ( int ) ( sqrt ( ( ( gxx + gyy ) + ( gxx - gyy ) * cos ( 2 * theta ) + 2 * gxy * sin ( 2 * theta ) ) / 2.0 ) + 0.5 ) ; // Gradient Magnitude
# else
// Koschan & Abidi - 2005 - Signal Processing Magazine
double theta = atan2 ( 2.0 * gxy , ( double ) ( gxx - gyy ) ) / 2 ; // Gradient Direction
double cosTheta = cos ( theta ) ;
double sinTheta = sin ( theta ) ;
int grad = ( int ) ( sqrt ( gxx * cosTheta * cosTheta + 2 * gxy * sinTheta * cosTheta + gyy * sinTheta * sinTheta ) + 0.5 ) ; // Gradient Magnitude
# endif
// Gradient is perpendicular to the edge passing through the pixel
if ( theta > = - 3.14159 / 4 & & theta < = 3.14159 / 4 )
dirImg [ i * width + j ] = EDGE_VERTICAL ;
else
dirImg [ i * width + j ] = EDGE_HORIZONTAL ;
gradImg [ i * width + j ] = ( ushort ) grad ;
if ( grad > max )
max = grad ;
}
}
// Scale the gradient values to 0-255
double scale = 255.0 / max ;
for ( int i = 0 ; i < width * height ; i + + )
gradImg [ i ] = ( ushort ) ( gradImg [ i ] * scale ) ;
}
void EdgeDrawingImpl : : smoothChannel ( const Mat & src , Mat & dst , double sigma )
{
if ( sigma = = 1.0 )
GaussianBlur ( src , dst , Size ( 5 , 5 ) , 1 ) ;
else if ( sigma = = 1.5 )
GaussianBlur ( src , dst , Size ( 7 , 7 ) , 1.5 ) ; // seems to be better?
else
GaussianBlur ( src , dst , Size ( ) , sigma ) ;
}
//---------------------------------------------------------
// Fix edge segments having one or two pixel fluctuations
// An example one pixel problem getting fixed:
// x
// x x --> xxx
//
// An example two pixel problem getting fixed:
// xx
// x x --> xxxx
//
void EdgeDrawingImpl : : fixEdgeSegments ( std : : vector < std : : vector < cv : : Point > > map )
{
/// First fix one pixel problems: There are four cases
for ( int i = 0 ; i < ( int ) map . size ( ) ; i + + ) {
int cp = ( int ) map [ i ] . size ( ) - 2 ; // Current pixel index
int n2 = 0 ; // next next pixel index
while ( n2 < ( int ) map [ i ] . size ( ) ) {
int n1 = cp + 1 ; // next pixel
cp = cp % map [ i ] . size ( ) ; // Roll back to the beginning
n1 = n1 % map [ i ] . size ( ) ; // Roll back to the beginning
int r = map [ i ] [ cp ] . y ;
int c = map [ i ] [ cp ] . x ;
int r1 = map [ i ] [ n1 ] . y ;
int c1 = map [ i ] [ n1 ] . x ;
int r2 = map [ i ] [ n2 ] . y ;
int c2 = map [ i ] [ n2 ] . x ;
// 4 cases to fix
if ( r2 = = r - 2 & & c2 = = c ) {
if ( c1 ! = c ) {
map [ i ] [ n1 ] . x = c ;
}
cp = n2 ;
n2 + = 2 ;
}
else if ( r2 = = r + 2 & & c2 = = c ) {
if ( c1 ! = c ) {
map [ i ] [ n1 ] . x = c ;
}
cp = n2 ;
n2 + = 2 ;
}
else if ( r2 = = r & & c2 = = c - 2 ) {
if ( r1 ! = r ) {
map [ i ] [ n1 ] . y = r ;
}
cp = n2 ;
n2 + = 2 ;
}
else if ( r2 = = r & & c2 = = c + 2 ) {
if ( r1 ! = r ) {
map [ i ] [ n1 ] . y = r ;
}
cp = n2 ;
n2 + = 2 ;
}
else {
cp + + ;
n2 + + ;
}
}
}
}
void EdgeDrawingImpl : : InitColorEDLib ( )
{
if ( LUT_Initialized )
return ;
double inc = 1.0 / LUT_SIZE ;
for ( int i = 0 ; i < = LUT_SIZE ; i + + ) {
double d = i * inc ;
if ( d > = 0.04045 ) LUT1 [ i ] = pow ( ( ( d + 0.055 ) / 1.055 ) , 2.4 ) ;
else LUT1 [ i ] = d / 12.92 ;
}
inc = 1.0 / LUT_SIZE ;
for ( int i = 0 ; i < = LUT_SIZE ; i + + ) {
double d = i * inc ;
if ( d > 0.008856 ) LUT2 [ i ] = pow ( d , 1.0 / 3.0 ) ;
else LUT2 [ i ] = ( 7.787 * d ) + ( 16.0 / 116.0 ) ;
}
LUT_Initialized = true ;
}
bool EdgeDrawingImpl : : LUT_Initialized = false ;
double EdgeDrawingImpl : : LUT1 [ LUT_SIZE + 1 ] = { 0 } ;
double EdgeDrawingImpl : : LUT2 [ LUT_SIZE + 1 ] = { 0 } ;
} // namespace cv
} // namespace ximgproc