EX2: 用CImg改写canny算法 EX2

1. canny.h

#ifndef _CANNY_
#define _CANNY_
#include "CImg.h"
#include <vector>

using namespace std;
using namespace cimg_library;

class canny {
private:
    CImg<unsigned char> img; //Original Image
    CImg<unsigned char> grayscaled; // Grayscale
    CImg<unsigned char> gFiltered; // Gradient
    CImg<unsigned char> sFiltered; //Sobel Filtered
    CImg<unsigned char> angles; //Angle Map
    CImg<unsigned char> non; // Non-maxima supp.
    CImg<unsigned char> thres; //Double threshold and final
public:
    canny(char const*); //Constructor
    CImg<unsigned char> toGrayScale();
    vector<vector<double> > createFilter(int, int, double); //Creates a gaussian filter
    CImg<unsigned char> useFilter(CImg<unsigned char>, vector<vector<double> >); //Use some filter
    CImg<unsigned char> sobel(); //Sobel filtering
    CImg<unsigned char> nonMaxSupp(); //Non-maxima supp.
    CImg<unsigned char> threshold(CImg<unsigned char>, int, int); //Double threshold and finalize picture
};

#endif

2. canny.cpp

Z
#define _USE_MATH_DEFINES
#include "canny.h"
#include <vector>
#include <iostream>

using namespace std; 
canny::canny(char const* filename)
{
    CImg<unsigned char> temp(filename);
    img = temp;

    if (0) // Check for invalid input
    {
        cout << "Could not open or find the image" << std::endl;
    }
    else
    {
        vector<vector<double> > filter = createFilter(3, 3, 1);

        //Print filter
        for (int i = 0; i<filter.size(); i++) 
        {
            for (int j = 0; j<filter[i].size(); j++) 
            {
                cout << filter[i][j] << " ";
            }
        }
        grayscaled = toGrayScale(); //Grayscale the image
        gFiltered = useFilter(grayscaled, filter); //Gaussian Filter
        sFiltered = sobel(); //Sobel Filter

        non = nonMaxSupp(); //Non-Maxima Suppression
        thres = threshold(non, 77, 95); //Double Threshold and Finalize 20 40

        /***************way1 to display*******************/
        CImgDisplay img_disp(img, "Original"),
                    grayscaled_disp(grayscaled,"GrayScaled"),
                    gFiltered_disp(gFiltered, "Gaussian Blur"),
                    sFiltered_disp(sFiltered, "Sobel Filtered"),
                    non_disp(non, "Non-Maxima Supp."),
                    thres_disp(thres, "Final");
        while (!img_disp.is_closed()
                || !grayscaled_disp.is_closed()
                || !gFiltered_disp.is_closed()
                || !sFiltered_disp.is_closed()
                || !non_disp.is_closed()
                || !thres_disp.is_closed()) {
        }
    }
}


CImg<unsigned char> canny::toGrayScale() {
    grayscaled = CImg<unsigned char>(img.rows, img.cols, 1); // one channel
    cimg_forXY(img, x, y) 
    {
        int b = img(x, y, 0);
        int g = img(x, y, 1);
        int r = img(x, y, 2);
        double newValue = (r * 0.2126 + g * 0.7152 + b * 0.0722);
        grayscaled(x, y) = newValue;
    }
    return grayscaled;
}

vector<vector<double>> canny::createFilter(int row, int column, double sigmaIn)
{
    vector<vector<double>> filter(row, vector<int>double(col, -1));

    int row = img.row;
    int col = img.col;
    float coordSum = 0;
    float constant = 2.0 * sigmaIn * sigmaIn;

    // Sum is for normalization
    float sum = 0.0;

    for (int x = - row/2; x <= row/2; x++)
    {
        for (int y = -column/2; y <= column/2; y++)
        {
            coordSum = (x*x + y*y);
            filter[x + row/2][y + column/2] = (exp(-(coordSum) / constant)) / (M_PI * constant);
            sum += filter[x + row/2][y + column/2];
        }
    }

    // Normalize the Filter
    for (int i = 0; i < row; i++)
        for (int j = 0; j < column; j++)
            filter[i][j] /= sum;

    return filter;
}

CImg<unsigned char> canny::useFilter(CImg<unsigned char> img_in, vector<vector<double>> filterIn)
{
    int size = (int)filterIn.size()/2;
    CImg<unsigned char> filteredImg = CImg<unsigned char>(img_in.rows - 2*size, img_in.cols - 2*size, 1);
    for (int i = size; i < img_in.rows - size; i++)
    {
        for (int j = size; j < img_in.cols - size; j++)
        {
            double sum = 0;
            
            for (int x = 0; x < filterIn.size(); x++)
                for (int y = 0; y < filterIn.size(); y++)
                {
                    sum += filterIn[x][y] * (double)(img_in(i + x - size, j + y - size));
                }
            
            filteredImg(i-size, j-size) = sum;
        }

    }
    return filteredImg;
}

CImg<unsigned char> canny::sobel()
{

    //Sobel X Filter
    double x1[] = {-1.0, 0, 1.0};
    double x2[] = {-2.0, 0, 2.0};
    double x3[] = {-1.0, 0, 1.0};

    vector<vector<double>> xFilter(3);
    xFilter[0].assign(x1, x1+3);
    xFilter[1].assign(x2, x2+3);
    xFilter[2].assign(x3, x3+3);
    
    //Sobel Y Filter
    double y1[] = {1.0, 2.0, 1.0};
    double y2[] = {0, 0, 0};
    double y3[] = {-1.0, -2.0, -1.0};
    
    vector<vector<double>> yFilter(3);
    yFilter[0].assign(y1, y1+3);
    yFilter[1].assign(y2, y2+3);
    yFilter[2].assign(y3, y3+3);
    
    //Limit Size
    int size = (int)xFilter.size()/2;
    
    CImg<unsigned char> filteredImg = CImg<unsigned char>(gFiltered.rows - 2*size, gFiltered.cols - 2*size);
    
    angles = CImg<unsigned char>(gFiltered.rows - 2*size, gFiltered.cols - 2*size, 1); //AngleMap

    for (int i = size; i < gFiltered.rows - size; i++)
    {
        for (int j = size; j < gFiltered.cols - size; j++)
        {
            double sumx = 0;
            double sumy = 0;
            
            for (int x = 0; x < xFilter.size(); x++)
                for (int y = 0; y < xFilter.size(); y++)
                {
                    sumx += xFilter[x][y] * (double)(gFiltered(i + x - size, j + y - size)); //Sobel_X Filter Value
                    sumy += yFilter[x][y] * (double)(gFiltered(i + x - size, j + y - size)); //Sobel_Y Filter Value
                }
            double sumxsq = sumx*sumx;
            double sumysq = sumy*sumy;
            
            double sq2 = sqrt(sumxsq + sumysq);
            
            if(sq2 > 255) //Unsigned Char Fix
                sq2 =255;
            filteredImg(i-size, j-size) = sq2;
 
            if(sumx==0) //Arctan Fix
                angles(i-size, j-size) = 90;
            else
                angles(i-size, j-size) = atan(sumy/sumx);
        }
    }
    
    return filteredImg;
}


CImg<unsigned char> canny::nonMaxSupp()
{
    CImg<unsigned char> nonMaxSupped = CImg<unsigned char>(sFiltered.rows-2, sFiltered.cols-2, CV_8UC1);
    for (int i=1; i<sFiltered.rows - 1; i++) {
        for (int j=1; j<sFiltered.cols - 1; j++) {
            float Tangent = angles(i,j);

            nonMaxSupped(i-1, j-1) = sFiltered(i,j);
            //Horizontal Edge
            if (((-22.5 < Tangent) && (Tangent <= 22.5)) || ((157.5 < Tangent) && (Tangent <= -157.5)))
            {
                if ((sFiltered(i,j) < sFiltered(i,j+1)) || (sFiltered(i,j) < sFiltered<uchar>(i,j-1)))
                    nonMaxSupped<uchar>(i-1, j-1) = 0;
            }
            //Vertical Edge
            if (((-112.5 < Tangent) && (Tangent <= -67.5)) || ((67.5 < Tangent) && (Tangent <= 112.5)))
            {
                if ((sFiltered.at(i,j) < sFiltered(i+1,j)) || (sFiltered(i,j) < sFiltered(i-1,j)))
                    nonMaxSupped.at(i-1, j-1) = 0;
            }
            
            //-45 Degree Edge
            if (((-67.5 < Tangent) && (Tangent <= -22.5)) || ((112.5 < Tangent) && (Tangent <= 157.5)))
            {
                if ((sFiltered(i,j) < sFiltered(i-1,j+1)) || (sFiltered(i,j) < sFiltered(i+1,j-1)))
                    nonMaxSupped.at<uchar>(i-1, j-1) = 0;
            }
            
            //45 Degree Edge
            if (((-157.5 < Tangent) && (Tangent <= -112.5)) || ((22.5 < Tangent) && (Tangent <= 67.5)))
            {
                if ((sFiltered(i,j) < sFiltered(i+1,j+1)) || (sFiltered(i,j) < sFiltered(i-1,j-1)))
                    nonMaxSupped(i-1, j-1) = 0;
            }
        }
    }
    return nonMaxSupped;
}

CImg<unsigned char> canny::threshold(CImg<unsigned char> imgin,int low, int high)
{
    if(low > 255)
        low = 255;
    if(high > 255)
        high = 255;
    
    CImg<unsigned char> EdgeMat = CImg<unsigned char>(imgin.rows, imgin.cols, imgin.type());
    
    for (int i=0; i<imgin.rows; i++) 
    {
        for (int j = 0; j<imgin.cols; j++) 
        {
            EdgeMat(i,j) = imgin(i,j);
            if(EdgeMat(i,j) > high)
                EdgeMat(i,j) = 255;
            else if(EdgeMat(i,j) < low)
                EdgeMat(i,j) = 0;
            else
            {
                bool anyHigh = false;
                bool anyBetween = false;
                for (int x=i-1; x < i+2; x++) 
                {
                    for (int y = j-1; y<j+2; y++) 
                    {
                        if(x <= 0 || y <= 0 || EdgeMat.rows || y > EdgeMat.cols) //Out of bounds
                            continue;
                        else
                        {
                            if(EdgeMat(x,y) > high)
                            {
                                EdgeMat(i,j) = 255;
                                anyHigh = true;
                                break;
                            }
                            else if(EdgeMat(x,y) <= high && EdgeMat(x,y) >= low)
                                anyBetween = true;
                        }
                    }
                    if(anyHigh)
                        break;
                }
                if(!anyHigh && anyBetween)
                    for (int x=i-2; x < i+3; x++) 
                    {
                        for (int y = j-1; y<j+3; y++) 
                        {
                            if(x < 0 || y < 0 || x > EdgeMat.rows || y > EdgeMat.cols) //Out of bounds
                                continue;
                            else
                            {
                                if(EdgeMat(x,y) > high)
                                {
                                    EdgeMat(i,j) = 255;
                                    anyHigh = true;
                                    break;
                                }
                            }
                        }
                        if(anyHigh)
                            break;
                    }
                if(!anyHigh)
                    EdgeMat(i,j) = 0;
            }
        }
    }
    return EdgeMat;
}

3. 运行效果

3.1 lena


3.2 bigben


3.3 stpetro



3.4 twows


4. 参数说明

4.1 toGrayScale

主要在于double newValue = (r * 0.2126 + g * 0.7152 + b * 0.0722);这句话,把每个点转为灰色

4.2 高斯模糊

首先调用createFilter生成卷积核,再用useFilter对图像进行卷积

4.3 sobel

用Gx和Gy两个卷积核对图像进行卷积,得到梯度变化大的边界。再用非极大值抑制法剔除非边缘的点。

4.4 双阈值法

剔除那些梯度变化过小或过大的点,以消除噪声

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,117评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,963评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,897评论 0 240
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,805评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,208评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,535评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,797评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,493评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,215评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,477评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,988评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,325评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,971评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,807评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,544评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,455评论 2 266

推荐阅读更多精彩内容