OpenCV Canny source Annotation and analysis

Source: Internet
Author: User
Tags bitwise

OpenCV Canny source annotation and Analysis
in 1986, John F.canny perfected the theory of edge detection, which is named after the Canny algorithm.
Steps for the Canny algorithm:
1. Noise reduction using filter convolution
2. Calculate the gradient amplitude and direction using the Sobel derivative
3. Non-maximum rejection + lag threshold value
Before the formal processing, using the Gaussian filter smoothing wave filter To do the filtering noise reduction operation, avoids the noise point interference, but in OpenCV's canny source code, does not carry on the Gaussian filter, needs the user to filter by itself; Some data consider the non-maximum suppression and hysteresis thresholds as two steps is also feasible, However, the non-Maxima and hysteresis thresholds in the source code are simultaneous.
Canny source location: \opencv\sources\modules\imgproc\src\canny.cpprefer to the online a lot of information, there are shortcomings please correct me, thank you.

/*m///////////////////////////////////////////////////////////////////////////////////////////Important:read  Before downloading, COPYING, installing or using.////by downloading, COPYING, installing or USING the software you agree                        To this license.//If agree to this license, does not download, install,//copy or use the software.////// Intel License agreement//for Open Source computer Vision library////Copyright (C) 200 0, Intel Corporation, all rights reserved.//third party copyrights is property of their respective owners.////Redistrib Ution and use in source and binary forms, with or without modification,//is permitted provided that the following Condit Ions is met:////* redistribution ' s of source code must retain the above copyright notice,//this list of condition S and the following disclaimer.////* redistribution ' s in binary form must reproduce the above copyright notice,//T His list of conditions and the following Disclaimer in the documentation//and/or all materials provided with the distribution.////* The name of the Tel Corporation May is used to endorse or promote products//derived from this software without specific prior WRI Tten permission.////This software are provided by the copyright holders and contributors ' as is ' and//any express or Impl IED warranties, including, but not limited to, the implied//warranties of merchantability and fitness for a particular PU Rpose is disclaimed.//in no event shall the Intel Corporation or contributors is liable for any direct,//indirect, Inci Dental, special, exemplary, or consequential damages//(including, but not limited to, procurement of substitute goods or services;//loss of use, data, or profits; or business interruption) however caused//and on any theory of liability, whether in contract, strict liability,//or Tor T (including negligence or otherwise) arising in any on-the-off of//the use of this software, even if ADVIsed of the possibility of such damage.////m*/#include "precomp.hpp"/* #if defined (HAVE_IPP) && (Ipp_version_majo R >= 7) #define Use_ipp_canny 1#else#undef use_ipp_canny#endif*/#ifdef use_ipp_cannynamespace cv{static bool IppCanny (const mat& _SRC, mat& _dst, float low, float high)    {int size = 0, size1 = 0;    Ippisize ROI = {_src.cols, _src.rows};    IPPIFILTERSOBELNEGVERTGETBUFFERSIZE_8U16S_C1R (ROI, ippmsksize3x3, &size);    IPPIFILTERSOBELHORIZGETBUFFERSIZE_8U16S_C1R (ROI, ippmsksize3x3, &size1);    Size = Std::max (size, size1);    Ippicannygetsize (ROI, &size1);    Size = Std::max (size, size1);    Autobuffer<uchar> buf (size + 64);    uchar* buffer = alignptr ((uchar*) buf, 32);    Mat _dx (_src.rows, _src.cols, cv_16s); if (IPPIFILTERSOBELNEGVERTBORDER_8U16S_C1R (_src.data, (int) _src.step, _dx.ptr<short> (), (int) _dx.    Step, ROI, ippmsksize3x3, IPPBORDERREPL, 0, buffer) < 0) return false; MAt _dy (_src.rows, _src.cols, cv_16s); if (IPPIFILTERSOBELHORIZBORDER_8U16S_C1R (_src.data, (int) _src.step, _dy.ptr<short> (), (int) _dy.st    EP, ROI, ippmsksize3x3, IPPBORDERREPL, 0, buffer) < 0) return false; if (IPPICANNY_16S8U_C1R (_dx.ptr<short> (), (int) _dx.step, _dy.ptr<short> (), (int) _dy    . Step, _dst.data, (int) _dst.step, ROI, Low, high, buffer) < 0) return false; return true;}}                #endifvoid Cv::canny (Inputarray _src, Outputarray _dst, double Low_thresh, double High_thresh,           int aperture_size, bool l2gradient) {Mat src = _src.getmat (); The input image must be a single-channel grayscale figure Cv_assert (src.depth () = = cv_8u);    8-bit unsigned _dst.create (src.size (), cv_8u);           Constructs the target matrix according to the SRC size DST Mat DST = _dst.getmat (); Output image, for single-channel black/White Graph//Low_thresh for low threshold, High_thresh for high threshold//aperture_size for operator size, default to 3//l2gradient to calculate gradient amplitudeIdentity, default is false//if L2gradient is false and Apeture_size has a value of-1 (-1 of binary ID: 1111 1111)//L2gradient is false then the Sobel derivative is calculated with G = | gx|+|    gy| L2gradient is true when calculating the Sobel derivative, use G = math.sqrt ((Gx) ^2 + (Gy) ^2) to open square if (! L2gradient && (aperture_size & cv_canny_l2_gradient) = = cv_canny_l2_gradient) {//Cv_canny_l2_gradient macros define their Value is: value = (1<<31) 1 shift left 31-bit is 2147483648//backward compatibility//~ Identity bitwise take REVERSE aperture_size & = ~cv_canny_l2_gradient;    L2gradient = true; }//Discriminant condition 1:aperture_size is an odd//discriminant condition 2:aperture_size range should be [3,7], default value 3 if (aperture_size & 1) = = 0 | |        (Aperture_size! =-1 && (Aperture_size < 3 | | aperture_size > 7)))  Cv_error (Cv_stsbadflag, ""); Error if (Low_thresh > High_thresh)//If low threshold value > High threshold Std::swap (Low_thresh, High_thresh); The Exchange low threshold and high threshold values #ifdef have_tegra_optimization if (Tegra::canny (SRC, DST, Low_thresh, High_thresh, Aperture_size, L2gradie NT)) return; #endif #ifdeF Use_ipp_canny if (aperture_size = = 3 &&!  L2gradient && ippcanny (SRC, DST, (float) Low_thresh, (float) high_thresh)) return; #endif const INT           cn = Src.channels (); CN is the number of channels for the input image Mat DX (src.rows, Src.cols, CV_16SC (CN)); Matrix storing X-directional Party wizards, CV_16SC (CN): 16-bit signed CN channel Mat DY (src.rows, Src.cols, CV_16SC (CN));        A matrix that stores the number of Y-direction Party wizards .../*sobel parameter description: (Reference Cvsobel) cvsobel (const cvarr* SRC,//input image cvarr* DST,//input image int Xorder,//x-direction derivative order int Yorde    R,//y-direction derivative of the order int aperture_size = 3//The width and height of the filter must be an odd number); *///border_replicate indicates that pixels at the edge of the original image are copied when the convolution point is at the boundary of the image, and the size of the original map is expanded with the copied pixels//The number of Sobel sides in the x direction is calculated, and the result exists in DX Sobel (src, DX, cv_     16S, 1, 0, aperture_size, 1, 0, cv::border_replicate);     Calculates the number of Sobel-side wizards in the Y direction, the results of which exist in Dy Sobel (src, dy, cv_16s, 0, 1, aperture_size, 1, 0, cv::border_replicate); When L2gradient is true, it means that the square root is required to openThe square operation, the threshold value also needs the square if (l2gradient) {Low_thresh = Std::min (32767.0, Low_thresh);        High_thresh = Std::min (32767.0, High_thresh);    if (Low_thresh > 0) low_thresh *= Low_thresh; Low threshold squared operation if (High_thresh > 0) high_thresh *= High_thresh;   High threshold value squared operation} int low = Cvfloor (Low_thresh);    Cvfloor returns the maximum integer value not greater than the parameter, equivalent to rounding int high = Cvfloor (High_thresh); ptrdiff_t is a data type defined in the C/S standard library, signed type, typically used to store two pointers of difference (distance), can be negative//mapstep for storing ptrdiff_t mapstep = Src.cols + 2; +2 means that the left and right extension of a side//autobuffer<uchar> will automatically allocate a certain size of memory, and specify that the data type in memory is UCHAR//number of columns +2 means the image expands one edge to the left (for copying edge pixels, enlarging the original image)//Line number +2 indicates that the image expands one edge at a autobuffer<uchar> buffer ((src.cols+2) * (src.rows+2) + CN * Mapstep * 3 * sizeof (int    )); int* Mag_buf[3];    Defines an int pointer array of size 3, mag_buf[0] = (int*) (uchar*) buffer;    MAG_BUF[1] = mag_buf[0] + mapstep*cn;    MAG_BUF[2] = mag_buf[1] + mapstep*cn;    memset (Mag_buf[0], 0,/* cn* */mapstep*sizeof (int)); uchar* map = (uchar*)(Mag_buf[2] + MAPSTEP*CN);    memset (map, 1, mapstep);    memset (map + mapstep* (src.rows + 1), 1, mapstep); int maxsize = Std::max (1 <<, Src.cols * SRC.ROWS/10); 2 of 10 Power std::vector<uchar*> stack (maxsize);      Defines the pointer type vector for the save address uchar **stack_top = &stack[0];   Stack-top pointer (pointer to pointer), point to stack[0], stack[0] is also a pointer uchar **stack_bottom = &stack[0];    Stack-bottom pointer, initial stack-bottom pointer = = Stack top pointer//gradient direction is approximated to one of four angles (0, 45, 90, 1354 selected)/* Sector numbers (Top-left Origin) 1 2 3 * * * * * * * 0*******0 * * * * * * 3 2 1 *///D Efine definition function block//Canny_push (d) is a stack function, the parameter d is the address pointer, so that the pointer to the content of an integer 2, into the stack, the top of the stack pointer +1//2 means that the pixel belongs to an edge can be seen below the note//Canny_pop (d) is The stack function, D points to the bottom pointer #define CANNY_PUSH (d) * (d) = Uchar (2), *stack_top++ = (d) #define CANNY_POP (d) (d) = *--stack_t    OP//Calculate magnitude and angle of gradient, perform non-maxima suppression. Fill the map with one of the following Values://0-the pixel might belong to an edge may belong to the edge//1-the pixel can not belong to an edge does not belong to the edge//  2-the pixel does belong to an edge must belong to the edge//for the non-maxima suppression + Lag threshold processing for (int i = 0; I <= src.rows; i++)//  I denotes line I {//I = = 0 o'clock, _norm points to mag_buf[1]//i > 0 o'clock, _norm to mag_buf[2]//+1 means skipping the first element of each line, since it is the edge after the extension, it cannot be the edges int* _norm                 = mag_buf[(i > 0) + 1] + 1; if (I < src.rows) {short* _dx = dx.ptr<short> (i);//_DX point to the DX matrix of line i short* _dy = dy. Ptr<short> (i); _dy points to the I line of the DY matrix if (!                     L2gradient)//If L2gradient is false {for (int j = 0; J < Src.cols*cn, j + +)//evaluates every value in line I _NORM[J] = std::abs (int (_dx[j])) + std::abs (int (_dy[j))); by | | +|| Calculation} else {for (int j = 0; J < Src.cols*cn; J + +)//squared calculation, when L2gradient is True, the high and low thresholds are squared, so here _norm[j] no need to open square _norm[j] = Int (_dx[j]) *_dx[j] + int (_dy[j]) *_dy[j]; } if (CN > 1)//If it is not a single channel (since the input image must be a single channel, so the individual feels this if is not true) {for (int j = 0 , JN = 0; J < Src.cols;                    ++j, JN + = cn) {int maxidx = JN;                    for (int k = 1; k < cn; ++k) if (_norm[jn + K] > _norm[maxidx]) maxidx = jn + k;                    _NORM[J] = _norm[maxidx];                    _DX[J] = _dx[maxidx];                _DY[J] = _dy[maxidx]; }} _norm[-1] = _norm[src.cols] = 0; The gradient amplitude of the last column and the first column is set to 0}//When i = = Src.rows (last row), the request space and the value of each space is initialized to 0, stored in mag_buf[2] else me         Mset (_norm-1, 0,/* cn* */mapstep*sizeof (int));        At the very beginning we don't have a complete ring//buffer of 3 magnitude rows for Non-maxima suppression        if (i = = 0) continue; uchar* _map = map + mapstep*i + 1; _map points to line i+1, +1 means that the first element of the row is skipped _map[-1] = _map[src.cols] = 1;        The first column and the last column are not edges, so set to 1 int* _mag = mag_buf[1] + 1;        Take the middle row of the central row ptrdiff_t magstep1 = mag_buf[2]-mag_buf[1];        ptrdiff_t MAGSTEP2 = mag_buf[0]-mag_buf[1];        Const short* _x = dx.ptr<short> (i-1);  Const short* _y = dy.ptr<short> (i-1);//If the stack size is not enough, re-allocate memory for the stack (equivalent to expand capacity) if ((Stack_top-stack_bottom) + Src.cols            > maxsize) {int sz = (int) (stack_top-stack_bottom);            MaxSize = maxsize * 3/2;            Stack.resize (MAXSIZE);            Stack_bottom = &stack[0];        Stack_top = Stack_bottom + sz; } int prev_flag = 0;            Previous Pixel point 0: Non-edge point; 1: Edge point for (int j = 0; J < Src.cols; J + +)//J Column {#define Canny_shift 15            tan22.5 const int TG22 = (int) (0.4142135623730950488016887242097* (1<<canny_shift) + 0.5);            int m = _mag[j];          if (M > Low)//If the threshold value is greater than      int xs = _x[j];    DX i-1 Line J column int ys = _y[j];                Dy in i-1 row j column int x = std::abs (xs);                int y = std::abs (ys) << Canny_shift;                int tg22x = x * TG22; if (Y < tg22x)//angle less than 22.5 is expressed in intervals: [0, 22.5) {////with the gradient amplitude of the left and right two points, if larger than left and right (the current point is the maximum value in the left and the neighboring neighborhood), then Goto __o                Cv_canny_push perform a stack operation if (M > _mag[j-1] && m >= _mag[j+1]) goto __ocv_canny_push; } else//angle greater than 22.5 {int tg67x = tg22x + (x << (canny_shift+                    1)); if (Y > tg67x)//(67.5, 90) {////vs. two-point gradient amplitude, if larger than up/down (at which point the current is The maximum value within the left and right neighborhood), Goto __ocv_canny_push performs a stack operation if (M > _mag[j+magstep2] && m >= _mag[j+mag                    Step1]) goto __ocv_canny_push;                } else//[22.5, 67.5] {    ^ Bitwise XOR if Xs and Ys take 1 otherwise take 1 int s = (xs ^ ys) < 0?                        -1:1; Compare diagonal Neighborhoods if (M > _mag[j+magstep2-s] && m > _mag[j+magstep1+s]) goto __ocv_canny_push                    ;            }}}//is lower than the current gradient amplitude low threshold and is directly identified as non-edge Prev_flag = 0; _MAP[J] = Uchar (1); 1 means not an edge Continue;__ocv_canny_push://The previous point is not an edge point and the current point's amplitude is greater than the high threshold and the point above it is not the edge point if            (!prev_flag && m > High && _map[j-mapstep]! = 2)                 {//Put the address of the current point into the stack, before entering the stack, the value of the point address is set to 2 (see the macro definition function block above) Canny_push (_map + j);            Prev_flag = 1;        } else _map[j] = 0; }//Scroll the ring buffer//swap the pointer to the position, overlay up, mag_[1] content to mag_buf[0]//mag_[2] to cover the contents of the mag_buf[1]        /finally let Mag_buf[2] point to the line that _mag points to _mag = mag_buf[0];        Mag_buf[0] = mag_buf[1]; Mag_bUF[1] = mag_buf[2];    MAG_BUF[2] = _mag; }//Now track the edges (hysteresis thresholding)//through the above for loop, determine the maximum points within each neighborhood as the edge point (labeled 2)///present, within the 8 neighborhood of these edge points (up and down +4        Diagonal), the possible edge points (labeled 0) are identified as edges while (Stack_top > Stack_bottom) {uchar* m;            if ((stack_top-stack_bottom) + 8 > MaxSize) {int sz = (int) (stack_top-stack_bottom);            MaxSize = maxsize * 3/2;            Stack.resize (MAXSIZE);            Stack_bottom = &stack[0];        Stack_top = Stack_bottom + sz; } canny_pop (M);        Out stack if (!m[-1]) Canny_push (m-1);        if (!m[1]) Canny_push (M + 1);        if (!m[-mapstep-1]) Canny_push (m-mapstep-1);        if (!m[-mapstep]) Canny_push (m-mapstep);        if (!m[-mapstep+1]) Canny_push (m-mapstep + 1);        if (!m[mapstep-1]) Canny_push (M + mapstep-1);        if (!m[mapstep]) Canny_push (M + mapstep);    if (!m[mapstep+1]) Canny_push (m + mapstep + 1); }//The FINAL Pass, form the final image//generate Edge Graph const uchar* PMAP = map + mapstep + 1;    uchar* PDST = Dst.ptr ();             for (int i = 0; i < src.rows; i++, Pmap + = Mapstep, pdst + = Dst.step) {for (int j = 0; J < Src.cols; J + +)    PDST[J] = (uchar)-(Pmap[j] >> 1);    }}void Cvcanny (const cvarr* image, cvarr* edges, double threshold1, double threshold2, int aperture_size) {    Cv::mat src = cv::cvarrtomat (image), DST = Cv::cvarrtomat (edges);    Cv_assert (src.size = = Dst.size && src.depth () = = cv_8u && dst.type () = = cv_8u); Cv::canny (SRC, DST, threshold1, Threshold2, Aperture_size & 255, Aperture_size & Cv_canny_l2_gradien T)! = 0);} /* End of file. */

OpenCV Canny source Annotation and analysis

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.