Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/325.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何检测圣诞树?_C++_Python_Opencv_Image Processing_Computer Vision_Php_Median - Fatal编程技术网

C++ 如何检测圣诞树?

C++ 如何检测圣诞树?,c++,python,opencv,image-processing,computer-vision,php,median,C++,Python,Opencv,Image Processing,Computer Vision,Php,Median,哪些图像处理技术可用于实现检测以下图像中显示的圣诞树的应用程序 我正在寻找能够处理所有这些图像的解决方案。因此,需要训练haar级联分类器或模板匹配的方法不是很有趣 我正在寻找可以用任何编程语言编写的东西,只要它只使用开源技术。必须使用此问题上共享的图像来测试解决方案。共有6个输入图像,答案应显示每个图像的处理结果。最后,对于每个输出图像,必须绘制红线以包围检测到的树 你将如何以编程方式检测这些图像中的树?< /P> < P> 编辑注释:< /强>我编辑了这个帖子(i)按要求按要求处理每

哪些图像处理技术可用于实现检测以下图像中显示的圣诞树的应用程序

我正在寻找能够处理所有这些图像的解决方案。因此,需要训练haar级联分类器或模板匹配的方法不是很有趣

我正在寻找可以用任何编程语言编写的东西,只要它只使用开源技术。必须使用此问题上共享的图像来测试解决方案。共有6个输入图像,答案应显示每个图像的处理结果。最后,对于每个输出图像,必须绘制红线以包围检测到的树


你将如何以编程方式检测这些图像中的树?< /P> < P> <强>编辑注释:< /强>我编辑了这个帖子(i)按要求按要求处理每个树图像,(ii)考虑对象亮度和形状,以提高结果的质量。p>


下面介绍了一种考虑对象亮度和形状的方法。换句话说,它寻找具有三角形形状和显著亮度的对象。它是用Java实现的,使用图像处理框架

第一步是颜色阈值。此处的目标是将分析重点放在具有显著亮度的对象上

输出图像:

public class ChristmasTree {

private MarvinImagePlugin fill = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.fill.boundaryFill");
private MarvinImagePlugin threshold = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.color.thresholding");
private MarvinImagePlugin invert = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.color.invert");
private MarvinImagePlugin dilation = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.morphological.dilation");

public ChristmasTree(){
    MarvinImage tree;

    // Iterate each image
    for(int i=1; i<=6; i++){
        tree = MarvinImageIO.loadImage("./res/trees/tree"+i+".png");

        // 1. Threshold
        threshold.setAttribute("threshold", 200);
        threshold.process(tree.clone(), tree);
    }
}
public static void main(String[] args) {
    new ChristmasTree();
}
}
public class ChristmasTree {

private MarvinImagePlugin fill = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.fill.boundaryFill");
private MarvinImagePlugin threshold = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.color.thresholding");
private MarvinImagePlugin invert = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.color.invert");
private MarvinImagePlugin dilation = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.morphological.dilation");

public ChristmasTree(){
    MarvinImage tree;

    // Iterate each image
    for(int i=1; i<=6; i++){
        tree = MarvinImageIO.loadImage("./res/trees/tree"+i+".png");

        // 1. Threshold
        threshold.setAttribute("threshold", 200);
        threshold.process(tree.clone(), tree);

        // 2. Dilate
        invert.process(tree.clone(), tree);
        tree = MarvinColorModelConverter.rgbToBinary(tree, 127);
        MarvinImageIO.saveImage(tree, "./res/trees/new/tree_"+i+"threshold.png");
        dilation.setAttribute("matrix", MarvinMath.getTrueMatrix(50, 50));
        dilation.process(tree.clone(), tree);
        MarvinImageIO.saveImage(tree, "./res/trees/new/tree_"+1+"_dilation.png");
        tree = MarvinColorModelConverter.binaryToRgb(tree);

        // 3. Segment shapes
        MarvinImage trees2 = tree.clone();
        fill(tree, trees2);
        MarvinImageIO.saveImage(trees2, "./res/trees/new/tree_"+i+"_fill.png");
}

private void fill(MarvinImage imageIn, MarvinImage imageOut){
    boolean found;
    int color= 0xFFFF0000;

    while(true){
        found=false;

        Outerloop:
        for(int y=0; y<imageIn.getHeight(); y++){
            for(int x=0; x<imageIn.getWidth(); x++){
                if(imageOut.getIntComponent0(x, y) == 0){
                    fill.setAttribute("x", x);
                    fill.setAttribute("y", y);
                    fill.setAttribute("color", color);
                    fill.setAttribute("threshold", 120);
                    fill.process(imageIn, imageOut);
                    color = newColor(color);

                    found = true;
                    break Outerloop;
                }
            }
        }

        if(!found){
            break;
        }
    }

}

private int newColor(int color){
    int red = (color & 0x00FF0000) >> 16;
    int green = (color & 0x0000FF00) >> 8;
    int blue = (color & 0x000000FF);

    if(red <= green && red <= blue){
        red+=5;
    }
    else if(green <= red && green <= blue){
        green+=5;
    }
    else{
        blue+=5;
    }

    return 0xFF000000 + (red << 16) + (green << 8) + blue;
}

public static void main(String[] args) {
    new ChristmasTree();
}
}
private int[] detectTrees(MarvinImage image){
    HashSet<Integer> analysed = new HashSet<Integer>();
    boolean found;
    while(true){
        found = false;
        for(int y=0; y<image.getHeight(); y++){
            for(int x=0; x<image.getWidth(); x++){
                int color = image.getIntColor(x, y);

                if(!analysed.contains(color)){
                    if(isTree(image, color)){
                        return getObjectRect(image, color);
                    }

                    analysed.add(color);
                    found=true;
                }
            }
        }

        if(!found){
            break;
        }
    }
    return null;
}

private boolean isTree(MarvinImage image, int color){

    int mass[][] = new int[image.getHeight()][2];
    int yStart=-1;
    int xStart=-1;
    for(int y=0; y<image.getHeight(); y++){
        int mc = 0;
        int xs=-1;
        int xe=-1;
        for(int x=0; x<image.getWidth(); x++){
            if(image.getIntColor(x, y) == color){
                mc++;

                if(yStart == -1){
                    yStart=y;
                    xStart=x;
                }

                if(xs == -1){
                    xs = x;
                }
                if(x > xe){
                    xe = x;
                }
            }
        }
        mass[y][0] = xs;
        mass[y][3] = xe;
        mass[y][4] = mc;    
    }

    int validLines=0;
    for(int y=0; y<image.getHeight(); y++){
        if
        ( 
            mass[y][5] > 0 &&
            Math.abs(((mass[y][0]+mass[y][6])/2)-xStart) <= 50 &&
            mass[y][7] >= (mass[yStart][8] + (y-yStart)*0.3) &&
            mass[y][9] <= (mass[yStart][10] + (y-yStart)*1.5)
        )
        {
            validLines++;
        }
    }

    if(validLines > 100){
        return true;
    }
    return false;
}
public class ChristmasTree {

private MarvinImagePlugin fill = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.fill.boundaryFill");
private MarvinImagePlugin threshold = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.color.thresholding");
private MarvinImagePlugin invert = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.color.invert");
private MarvinImagePlugin dilation = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.morphological.dilation");

public ChristmasTree(){
    MarvinImage tree;

    // Iterate each image
    for(int i=1; i<=6; i++){
        tree = MarvinImageIO.loadImage("./res/trees/tree"+i+".png");

        // 1. Threshold
        threshold.setAttribute("threshold", 200);
        threshold.process(tree.clone(), tree);

        // 2. Dilate
        invert.process(tree.clone(), tree);
        tree = MarvinColorModelConverter.rgbToBinary(tree, 127);
        MarvinImageIO.saveImage(tree, "./res/trees/new/tree_"+i+"threshold.png");
        dilation.setAttribute("matrix", MarvinMath.getTrueMatrix(50, 50));
        dilation.process(tree.clone(), tree);
        MarvinImageIO.saveImage(tree, "./res/trees/new/tree_"+1+"_dilation.png");
        tree = MarvinColorModelConverter.binaryToRgb(tree);

        // 3. Segment shapes
        MarvinImage trees2 = tree.clone();
        fill(tree, trees2);
        MarvinImageIO.saveImage(trees2, "./res/trees/new/tree_"+i+"_fill.png");

        // 4. Detect tree-like shapes
        int[] rect = detectTrees(trees2);

        // 5. Draw the result
        MarvinImage original = MarvinImageIO.loadImage("./res/trees/tree"+i+".png");
        drawBoundary(trees2, original, rect);
        MarvinImageIO.saveImage(original, "./res/trees/new/tree_"+i+"_out_2.jpg");
    }
}

private void drawBoundary(MarvinImage shape, MarvinImage original, int[] rect){
    int yLines[] = new int[6];
    yLines[0] = rect[1];
    yLines[1] = rect[1]+(int)((rect[3]/5));
    yLines[2] = rect[1]+((rect[3]/5)*2);
    yLines[3] = rect[1]+((rect[3]/5)*3);
    yLines[4] = rect[1]+(int)((rect[3]/5)*4);
    yLines[5] = rect[1]+rect[3];

    List<Point> points = new ArrayList<Point>();
    for(int i=0; i<yLines.length; i++){
        boolean in=false;
        Point startPoint=null;
        Point endPoint=null;
        for(int x=rect[0]; x<rect[0]+rect[2]; x++){

            if(shape.getIntColor(x, yLines[i]) != 0xFFFFFFFF){
                if(!in){
                    if(startPoint == null){
                        startPoint = new Point(x, yLines[i]);
                    }
                }
                in = true;
            }
            else{
                if(in){
                    endPoint = new Point(x, yLines[i]);
                }
                in = false;
            }
        }

        if(endPoint == null){
            endPoint = new Point((rect[0]+rect[2])-1, yLines[i]);
        }

        points.add(startPoint);
        points.add(endPoint);
    }

    drawLine(points.get(0).x, points.get(0).y, points.get(1).x, points.get(1).y, 15, original);
    drawLine(points.get(1).x, points.get(1).y, points.get(3).x, points.get(3).y, 15, original);
    drawLine(points.get(3).x, points.get(3).y, points.get(5).x, points.get(5).y, 15, original);
    drawLine(points.get(5).x, points.get(5).y, points.get(7).x, points.get(7).y, 15, original);
    drawLine(points.get(7).x, points.get(7).y, points.get(9).x, points.get(9).y, 15, original);
    drawLine(points.get(9).x, points.get(9).y, points.get(11).x, points.get(11).y, 15, original);
    drawLine(points.get(11).x, points.get(11).y, points.get(10).x, points.get(10).y, 15, original);
    drawLine(points.get(10).x, points.get(10).y, points.get(8).x, points.get(8).y, 15, original);
    drawLine(points.get(8).x, points.get(8).y, points.get(6).x, points.get(6).y, 15, original);
    drawLine(points.get(6).x, points.get(6).y, points.get(4).x, points.get(4).y, 15, original);
    drawLine(points.get(4).x, points.get(4).y, points.get(2).x, points.get(2).y, 15, original);
    drawLine(points.get(2).x, points.get(2).y, points.get(0).x, points.get(0).y, 15, original);
}

private void drawLine(int x1, int y1, int x2, int y2, int length, MarvinImage image){
    int lx1, lx2, ly1, ly2;
    for(int i=0; i<length; i++){
        lx1 = (x1+i >= image.getWidth() ? (image.getWidth()-1)-i: x1);
        lx2 = (x2+i >= image.getWidth() ? (image.getWidth()-1)-i: x2);
        ly1 = (y1+i >= image.getHeight() ? (image.getHeight()-1)-i: y1);
        ly2 = (y2+i >= image.getHeight() ? (image.getHeight()-1)-i: y2);

        image.drawLine(lx1+i, ly1, lx2+i, ly2, Color.red);
        image.drawLine(lx1, ly1+i, lx2, ly2+i, Color.red);
    }
}

private void fillRect(MarvinImage image, int[] rect, int length){
    for(int i=0; i<length; i++){
        image.drawRect(rect[0]+i, rect[1]+i, rect[2]-(i*2), rect[3]-(i*2), Color.red);
    }
}

private void fill(MarvinImage imageIn, MarvinImage imageOut){
    boolean found;
    int color= 0xFFFF0000;

    while(true){
        found=false;

        Outerloop:
        for(int y=0; y<imageIn.getHeight(); y++){
            for(int x=0; x<imageIn.getWidth(); x++){
                if(imageOut.getIntComponent0(x, y) == 0){
                    fill.setAttribute("x", x);
                    fill.setAttribute("y", y);
                    fill.setAttribute("color", color);
                    fill.setAttribute("threshold", 120);
                    fill.process(imageIn, imageOut);
                    color = newColor(color);

                    found = true;
                    break Outerloop;
                }
            }
        }

        if(!found){
            break;
        }
    }

}

private int[] detectTrees(MarvinImage image){
    HashSet<Integer> analysed = new HashSet<Integer>();
    boolean found;
    while(true){
        found = false;
        for(int y=0; y<image.getHeight(); y++){
            for(int x=0; x<image.getWidth(); x++){
                int color = image.getIntColor(x, y);

                if(!analysed.contains(color)){
                    if(isTree(image, color)){
                        return getObjectRect(image, color);
                    }

                    analysed.add(color);
                    found=true;
                }
            }
        }

        if(!found){
            break;
        }
    }
    return null;
}

private boolean isTree(MarvinImage image, int color){

    int mass[][] = new int[image.getHeight()][11];
    int yStart=-1;
    int xStart=-1;
    for(int y=0; y<image.getHeight(); y++){
        int mc = 0;
        int xs=-1;
        int xe=-1;
        for(int x=0; x<image.getWidth(); x++){
            if(image.getIntColor(x, y) == color){
                mc++;

                if(yStart == -1){
                    yStart=y;
                    xStart=x;
                }

                if(xs == -1){
                    xs = x;
                }
                if(x > xe){
                    xe = x;
                }
            }
        }
        mass[y][0] = xs;
        mass[y][12] = xe;
        mass[y][13] = mc;   
    }

    int validLines=0;
    for(int y=0; y<image.getHeight(); y++){
        if
        ( 
            mass[y][14] > 0 &&
            Math.abs(((mass[y][0]+mass[y][15])/2)-xStart) <= 50 &&
            mass[y][16] >= (mass[yStart][17] + (y-yStart)*0.3) &&
            mass[y][18] <= (mass[yStart][19] + (y-yStart)*1.5)
        )
        {
            validLines++;
        }
    }

    if(validLines > 100){
        return true;
    }
    return false;
}

private int[] getObjectRect(MarvinImage image, int color){
    int x1=-1;
    int x2=-1;
    int y1=-1;
    int y2=-1;

    for(int y=0; y<image.getHeight(); y++){
        for(int x=0; x<image.getWidth(); x++){
            if(image.getIntColor(x, y) == color){

                if(x1 == -1 || x < x1){
                    x1 = x;
                }
                if(x2 == -1 || x > x2){
                    x2 = x;
                }
                if(y1 == -1 || y < y1){
                    y1 = y;
                }
                if(y2 == -1 || y > y2){
                    y2 = y;
                }
            }
        }
    }

    return new int[]{x1, y1, (x2-x1), (y2-y1)};
}

private int newColor(int color){
    int red = (color & 0x00FF0000) >> 16;
    int green = (color & 0x0000FF00) >> 8;
    int blue = (color & 0x000000FF);

    if(red <= green && red <= blue){
        red+=5;
    }
    else if(green <= red && green <= blue){
        green+=30;
    }
    else{
        blue+=30;
    }

    return 0xFF000000 + (red << 16) + (green << 8) + blue;
}

public static void main(String[] args) {
    new ChristmasTree();
}
}

源代码:

public class ChristmasTree {

private MarvinImagePlugin fill = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.fill.boundaryFill");
private MarvinImagePlugin threshold = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.color.thresholding");
private MarvinImagePlugin invert = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.color.invert");
private MarvinImagePlugin dilation = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.morphological.dilation");

public ChristmasTree(){
    MarvinImage tree;

    // Iterate each image
    for(int i=1; i<=6; i++){
        tree = MarvinImageIO.loadImage("./res/trees/tree"+i+".png");

        // 1. Threshold
        threshold.setAttribute("threshold", 200);
        threshold.process(tree.clone(), tree);
    }
}
public static void main(String[] args) {
    new ChristmasTree();
}
}
public class ChristmasTree {

private MarvinImagePlugin fill = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.fill.boundaryFill");
private MarvinImagePlugin threshold = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.color.thresholding");
private MarvinImagePlugin invert = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.color.invert");
private MarvinImagePlugin dilation = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.morphological.dilation");

public ChristmasTree(){
    MarvinImage tree;

    // Iterate each image
    for(int i=1; i<=6; i++){
        tree = MarvinImageIO.loadImage("./res/trees/tree"+i+".png");

        // 1. Threshold
        threshold.setAttribute("threshold", 200);
        threshold.process(tree.clone(), tree);

        // 2. Dilate
        invert.process(tree.clone(), tree);
        tree = MarvinColorModelConverter.rgbToBinary(tree, 127);
        MarvinImageIO.saveImage(tree, "./res/trees/new/tree_"+i+"threshold.png");
        dilation.setAttribute("matrix", MarvinMath.getTrueMatrix(50, 50));
        dilation.process(tree.clone(), tree);
        MarvinImageIO.saveImage(tree, "./res/trees/new/tree_"+1+"_dilation.png");
        tree = MarvinColorModelConverter.binaryToRgb(tree);

        // 3. Segment shapes
        MarvinImage trees2 = tree.clone();
        fill(tree, trees2);
        MarvinImageIO.saveImage(trees2, "./res/trees/new/tree_"+i+"_fill.png");
}

private void fill(MarvinImage imageIn, MarvinImage imageOut){
    boolean found;
    int color= 0xFFFF0000;

    while(true){
        found=false;

        Outerloop:
        for(int y=0; y<imageIn.getHeight(); y++){
            for(int x=0; x<imageIn.getWidth(); x++){
                if(imageOut.getIntComponent0(x, y) == 0){
                    fill.setAttribute("x", x);
                    fill.setAttribute("y", y);
                    fill.setAttribute("color", color);
                    fill.setAttribute("threshold", 120);
                    fill.process(imageIn, imageOut);
                    color = newColor(color);

                    found = true;
                    break Outerloop;
                }
            }
        }

        if(!found){
            break;
        }
    }

}

private int newColor(int color){
    int red = (color & 0x00FF0000) >> 16;
    int green = (color & 0x0000FF00) >> 8;
    int blue = (color & 0x000000FF);

    if(red <= green && red <= blue){
        red+=5;
    }
    else if(green <= red && green <= blue){
        green+=5;
    }
    else{
        blue+=5;
    }

    return 0xFF000000 + (red << 16) + (green << 8) + blue;
}

public static void main(String[] args) {
    new ChristmasTree();
}
}
private int[] detectTrees(MarvinImage image){
    HashSet<Integer> analysed = new HashSet<Integer>();
    boolean found;
    while(true){
        found = false;
        for(int y=0; y<image.getHeight(); y++){
            for(int x=0; x<image.getWidth(); x++){
                int color = image.getIntColor(x, y);

                if(!analysed.contains(color)){
                    if(isTree(image, color)){
                        return getObjectRect(image, color);
                    }

                    analysed.add(color);
                    found=true;
                }
            }
        }

        if(!found){
            break;
        }
    }
    return null;
}

private boolean isTree(MarvinImage image, int color){

    int mass[][] = new int[image.getHeight()][2];
    int yStart=-1;
    int xStart=-1;
    for(int y=0; y<image.getHeight(); y++){
        int mc = 0;
        int xs=-1;
        int xe=-1;
        for(int x=0; x<image.getWidth(); x++){
            if(image.getIntColor(x, y) == color){
                mc++;

                if(yStart == -1){
                    yStart=y;
                    xStart=x;
                }

                if(xs == -1){
                    xs = x;
                }
                if(x > xe){
                    xe = x;
                }
            }
        }
        mass[y][0] = xs;
        mass[y][3] = xe;
        mass[y][4] = mc;    
    }

    int validLines=0;
    for(int y=0; y<image.getHeight(); y++){
        if
        ( 
            mass[y][5] > 0 &&
            Math.abs(((mass[y][0]+mass[y][6])/2)-xStart) <= 50 &&
            mass[y][7] >= (mass[yStart][8] + (y-yStart)*0.3) &&
            mass[y][9] <= (mass[yStart][10] + (y-yStart)*1.5)
        )
        {
            validLines++;
        }
    }

    if(validLines > 100){
        return true;
    }
    return false;
}
public class ChristmasTree {

private MarvinImagePlugin fill = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.fill.boundaryFill");
private MarvinImagePlugin threshold = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.color.thresholding");
private MarvinImagePlugin invert = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.color.invert");
private MarvinImagePlugin dilation = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.morphological.dilation");

public ChristmasTree(){
    MarvinImage tree;

    // Iterate each image
    for(int i=1; i<=6; i++){
        tree = MarvinImageIO.loadImage("./res/trees/tree"+i+".png");

        // 1. Threshold
        threshold.setAttribute("threshold", 200);
        threshold.process(tree.clone(), tree);

        // 2. Dilate
        invert.process(tree.clone(), tree);
        tree = MarvinColorModelConverter.rgbToBinary(tree, 127);
        MarvinImageIO.saveImage(tree, "./res/trees/new/tree_"+i+"threshold.png");
        dilation.setAttribute("matrix", MarvinMath.getTrueMatrix(50, 50));
        dilation.process(tree.clone(), tree);
        MarvinImageIO.saveImage(tree, "./res/trees/new/tree_"+1+"_dilation.png");
        tree = MarvinColorModelConverter.binaryToRgb(tree);

        // 3. Segment shapes
        MarvinImage trees2 = tree.clone();
        fill(tree, trees2);
        MarvinImageIO.saveImage(trees2, "./res/trees/new/tree_"+i+"_fill.png");

        // 4. Detect tree-like shapes
        int[] rect = detectTrees(trees2);

        // 5. Draw the result
        MarvinImage original = MarvinImageIO.loadImage("./res/trees/tree"+i+".png");
        drawBoundary(trees2, original, rect);
        MarvinImageIO.saveImage(original, "./res/trees/new/tree_"+i+"_out_2.jpg");
    }
}

private void drawBoundary(MarvinImage shape, MarvinImage original, int[] rect){
    int yLines[] = new int[6];
    yLines[0] = rect[1];
    yLines[1] = rect[1]+(int)((rect[3]/5));
    yLines[2] = rect[1]+((rect[3]/5)*2);
    yLines[3] = rect[1]+((rect[3]/5)*3);
    yLines[4] = rect[1]+(int)((rect[3]/5)*4);
    yLines[5] = rect[1]+rect[3];

    List<Point> points = new ArrayList<Point>();
    for(int i=0; i<yLines.length; i++){
        boolean in=false;
        Point startPoint=null;
        Point endPoint=null;
        for(int x=rect[0]; x<rect[0]+rect[2]; x++){

            if(shape.getIntColor(x, yLines[i]) != 0xFFFFFFFF){
                if(!in){
                    if(startPoint == null){
                        startPoint = new Point(x, yLines[i]);
                    }
                }
                in = true;
            }
            else{
                if(in){
                    endPoint = new Point(x, yLines[i]);
                }
                in = false;
            }
        }

        if(endPoint == null){
            endPoint = new Point((rect[0]+rect[2])-1, yLines[i]);
        }

        points.add(startPoint);
        points.add(endPoint);
    }

    drawLine(points.get(0).x, points.get(0).y, points.get(1).x, points.get(1).y, 15, original);
    drawLine(points.get(1).x, points.get(1).y, points.get(3).x, points.get(3).y, 15, original);
    drawLine(points.get(3).x, points.get(3).y, points.get(5).x, points.get(5).y, 15, original);
    drawLine(points.get(5).x, points.get(5).y, points.get(7).x, points.get(7).y, 15, original);
    drawLine(points.get(7).x, points.get(7).y, points.get(9).x, points.get(9).y, 15, original);
    drawLine(points.get(9).x, points.get(9).y, points.get(11).x, points.get(11).y, 15, original);
    drawLine(points.get(11).x, points.get(11).y, points.get(10).x, points.get(10).y, 15, original);
    drawLine(points.get(10).x, points.get(10).y, points.get(8).x, points.get(8).y, 15, original);
    drawLine(points.get(8).x, points.get(8).y, points.get(6).x, points.get(6).y, 15, original);
    drawLine(points.get(6).x, points.get(6).y, points.get(4).x, points.get(4).y, 15, original);
    drawLine(points.get(4).x, points.get(4).y, points.get(2).x, points.get(2).y, 15, original);
    drawLine(points.get(2).x, points.get(2).y, points.get(0).x, points.get(0).y, 15, original);
}

private void drawLine(int x1, int y1, int x2, int y2, int length, MarvinImage image){
    int lx1, lx2, ly1, ly2;
    for(int i=0; i<length; i++){
        lx1 = (x1+i >= image.getWidth() ? (image.getWidth()-1)-i: x1);
        lx2 = (x2+i >= image.getWidth() ? (image.getWidth()-1)-i: x2);
        ly1 = (y1+i >= image.getHeight() ? (image.getHeight()-1)-i: y1);
        ly2 = (y2+i >= image.getHeight() ? (image.getHeight()-1)-i: y2);

        image.drawLine(lx1+i, ly1, lx2+i, ly2, Color.red);
        image.drawLine(lx1, ly1+i, lx2, ly2+i, Color.red);
    }
}

private void fillRect(MarvinImage image, int[] rect, int length){
    for(int i=0; i<length; i++){
        image.drawRect(rect[0]+i, rect[1]+i, rect[2]-(i*2), rect[3]-(i*2), Color.red);
    }
}

private void fill(MarvinImage imageIn, MarvinImage imageOut){
    boolean found;
    int color= 0xFFFF0000;

    while(true){
        found=false;

        Outerloop:
        for(int y=0; y<imageIn.getHeight(); y++){
            for(int x=0; x<imageIn.getWidth(); x++){
                if(imageOut.getIntComponent0(x, y) == 0){
                    fill.setAttribute("x", x);
                    fill.setAttribute("y", y);
                    fill.setAttribute("color", color);
                    fill.setAttribute("threshold", 120);
                    fill.process(imageIn, imageOut);
                    color = newColor(color);

                    found = true;
                    break Outerloop;
                }
            }
        }

        if(!found){
            break;
        }
    }

}

private int[] detectTrees(MarvinImage image){
    HashSet<Integer> analysed = new HashSet<Integer>();
    boolean found;
    while(true){
        found = false;
        for(int y=0; y<image.getHeight(); y++){
            for(int x=0; x<image.getWidth(); x++){
                int color = image.getIntColor(x, y);

                if(!analysed.contains(color)){
                    if(isTree(image, color)){
                        return getObjectRect(image, color);
                    }

                    analysed.add(color);
                    found=true;
                }
            }
        }

        if(!found){
            break;
        }
    }
    return null;
}

private boolean isTree(MarvinImage image, int color){

    int mass[][] = new int[image.getHeight()][11];
    int yStart=-1;
    int xStart=-1;
    for(int y=0; y<image.getHeight(); y++){
        int mc = 0;
        int xs=-1;
        int xe=-1;
        for(int x=0; x<image.getWidth(); x++){
            if(image.getIntColor(x, y) == color){
                mc++;

                if(yStart == -1){
                    yStart=y;
                    xStart=x;
                }

                if(xs == -1){
                    xs = x;
                }
                if(x > xe){
                    xe = x;
                }
            }
        }
        mass[y][0] = xs;
        mass[y][12] = xe;
        mass[y][13] = mc;   
    }

    int validLines=0;
    for(int y=0; y<image.getHeight(); y++){
        if
        ( 
            mass[y][14] > 0 &&
            Math.abs(((mass[y][0]+mass[y][15])/2)-xStart) <= 50 &&
            mass[y][16] >= (mass[yStart][17] + (y-yStart)*0.3) &&
            mass[y][18] <= (mass[yStart][19] + (y-yStart)*1.5)
        )
        {
            validLines++;
        }
    }

    if(validLines > 100){
        return true;
    }
    return false;
}

private int[] getObjectRect(MarvinImage image, int color){
    int x1=-1;
    int x2=-1;
    int y1=-1;
    int y2=-1;

    for(int y=0; y<image.getHeight(); y++){
        for(int x=0; x<image.getWidth(); x++){
            if(image.getIntColor(x, y) == color){

                if(x1 == -1 || x < x1){
                    x1 = x;
                }
                if(x2 == -1 || x > x2){
                    x2 = x;
                }
                if(y1 == -1 || y < y1){
                    y1 = y;
                }
                if(y2 == -1 || y > y2){
                    y2 = y;
                }
            }
        }
    }

    return new int[]{x1, y1, (x2-x1), (y2-y1)};
}

private int newColor(int color){
    int red = (color & 0x00FF0000) >> 16;
    int green = (color & 0x0000FF00) >> 8;
    int blue = (color & 0x000000FF);

    if(red <= green && red <= blue){
        red+=5;
    }
    else if(green <= red && green <= blue){
        green+=30;
    }
    else{
        blue+=30;
    }

    return 0xFF000000 + (red << 16) + (green << 8) + blue;
}

public static void main(String[] args) {
    new ChristmasTree();
}
}
公共类圣诞树{
private MarvinImagePlugin fill=marvinpluginload.loadImagePlugin(“org.marvinproject.image.fill.boundaryFill”);
private MarvinImagePlugin threshold=marvinpluginload.loadImagePlugin(“org.marvinproject.image.color.thresholding”);
private MarvinImagePlugin invert=marvinpluginload.loadImagePlugin(“org.marvinproject.image.color.invert”);
private MarvinImagePlugin Distriction=MarvinPluginLoader.loadImagePlugin(“org.marvinproject.image.morphical.Distriction”);
公共圣诞树(){
马尔文图像树;
//迭代每个图像
对于(int i=1;i 8;
int蓝色=(颜色&0x000000FF);

如果(红色这里是我简单而愚蠢的解决方案。 这是基于这样一种假设,即树将是图片中最明亮、最大的东西

//g++ -Wall -pedantic -ansi -O2 -pipe -s -o christmas_tree christmas_tree.cpp `pkg-config --cflags --libs opencv`
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main(int argc,char *argv[])
{
    Mat original,tmp,tmp1;
    vector <vector<Point> > contours;
    Moments m;
    Rect boundrect;
    Point2f center;
    double radius, max_area=0,tmp_area=0;
    unsigned int j, k;
    int i;

    for(i = 1; i < argc; ++i)
    {
        original = imread(argv[i]);
        if(original.empty())
        {
            cerr << "Error"<<endl;
            return -1;
        }

        GaussianBlur(original, tmp, Size(3, 3), 0, 0, BORDER_DEFAULT);
        erode(tmp, tmp, Mat(), Point(-1, -1), 10);
        cvtColor(tmp, tmp, CV_BGR2HSV);
        inRange(tmp, Scalar(0, 0, 0), Scalar(180, 255, 200), tmp);

        dilate(original, tmp1, Mat(), Point(-1, -1), 15);
        cvtColor(tmp1, tmp1, CV_BGR2HLS);
        inRange(tmp1, Scalar(0, 185, 0), Scalar(180, 255, 255), tmp1);
        dilate(tmp1, tmp1, Mat(), Point(-1, -1), 10);

        bitwise_and(tmp, tmp1, tmp1);

        findContours(tmp1, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
        max_area = 0;
        j = 0;
        for(k = 0; k < contours.size(); k++)
        {
            tmp_area = contourArea(contours[k]);
            if(tmp_area > max_area)
            {
                max_area = tmp_area;
                j = k;
            }
        }
        tmp1 = Mat::zeros(original.size(),CV_8U);
        approxPolyDP(contours[j], contours[j], 30, true);
        drawContours(tmp1, contours, j, Scalar(255,255,255), CV_FILLED);

        m = moments(contours[j]);
        boundrect = boundingRect(contours[j]);
        center = Point2f(m.m10/m.m00, m.m01/m.m00);
        radius = (center.y - (boundrect.tl().y))/4.0*3.0;
        Rect heightrect(center.x-original.cols/5, boundrect.tl().y, original.cols/5*2, boundrect.size().height);

        tmp = Mat::zeros(original.size(), CV_8U);
        rectangle(tmp, heightrect, Scalar(255, 255, 255), -1);
        circle(tmp, center, radius, Scalar(255, 255, 255), -1);

        bitwise_and(tmp, tmp1, tmp1);

        findContours(tmp1, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
        max_area = 0;
        j = 0;
        for(k = 0; k < contours.size(); k++)
        {
            tmp_area = contourArea(contours[k]);
            if(tmp_area > max_area)
            {
                max_area = tmp_area;
                j = k;
            }
        }

        approxPolyDP(contours[j], contours[j], 30, true);
        convexHull(contours[j], contours[j]);

        drawContours(original, contours, j, Scalar(0, 0, 255), 3);

        namedWindow(argv[i], CV_WINDOW_NORMAL|CV_WINDOW_KEEPRATIO|CV_GUI_EXPANDED);
        imshow(argv[i], original);

        waitKey(0);
        destroyWindow(argv[i]);
    }

    return 0;
}
然后我们找到每个“明亮”像素:

最后,我们加入两个结果:

bitwise_and(tmp, tmp1, tmp1);
现在我们寻找最大的明亮物体:

findContours(tmp1, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
max_area = 0;
j = 0;
for(k = 0; k < contours.size(); k++)
{
    tmp_area = contourArea(contours[k]);
    if(tmp_area > max_area)
    {
        max_area = tmp_area;
        j = k;
    }
}
tmp1 = Mat::zeros(original.size(),CV_8U);
approxPolyDP(contours[j], contours[j], 30, true);
drawContours(tmp1, contours, j, Scalar(255,255,255), CV_FILLED);
最后一步是找到我们的树的轮廓,并把它画在原始图片上

findContours(tmp1, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
max_area = 0;
j = 0;
for(k = 0; k < contours.size(); k++)
{
    tmp_area = contourArea(contours[k]);
    if(tmp_area > max_area)
    {
        max_area = tmp_area;
        j = k;
    }
}

approxPolyDP(contours[j], contours[j], 30, true);
convexHull(contours[j], contours[j]);

drawContours(original, contours, j, Scalar(0, 0, 255), 3);
findContours(tmp1、等高线、等高线、等高线、等高线、等高线、等高线、等高线、等高线、等高线、等高线);
最大面积=0;
j=0;
对于(k=0;k最大面积)
{
最大面积=tmp面积;
j=k;
}
}
approxPolyDP(等高线[j],等高线[j],30,真);
凸形(等高线[j],等高线[j]);
绘制等高线(原始、等高线、j、标量(0、0、255)、3);
很抱歉,目前我的连接不好,因此无法上传图片。我会稍后再尝试

圣诞快乐

编辑:

以下是最终输出的一些图片:


一些老式的图像处理方法…
这个想法是基于这样一种假设的:图像描绘的是在通常较暗和较平滑的背景上被照亮的树木(在某些情况下是前景)。被照亮的树木区域更“充满活力”,强度更高
程序如下:

  • 转换为灰度
  • 应用日志筛选以获取最“活跃”的区域
  • 应用强度阈值以获得最亮的区域
  • 结合前面的2个,得到一个初步的遮罩
  • 应用形态扩张以扩大区域并连接相邻组件
  • 根据区域大小消除小的候选区域
  • 您得到的是一个二进制掩码和每个图像的边界框

    以下是使用这种简单技术的结果:

    MATLAB上的代码如下: 代码在包含JPG图像的文件夹上运行。加载所有图像并返回检测到的结果

    % clear everything
    clear;
    pack;
    close all;
    close all hidden;
    drawnow;
    clc;
    
    % initialization
    ims=dir('./*.jpg');
    imgs={};
    images={}; 
    blur_images={}; 
    log_image={}; 
    dilated_image={};
    int_image={};
    bin_image={};
    measurements={};
    box={};
    num=length(ims);
    thres_div = 3;
    
    for i=1:num, 
        % load original image
        imgs{end+1}=imread(ims(i).name);
    
        % convert to grayscale
        images{end+1}=rgb2gray(imgs{i});
    
        % apply laplacian filtering and heuristic hard thresholding
        val_thres = (max(max(images{i}))/thres_div);
        log_image{end+1} = imfilter( images{i},fspecial('log')) > val_thres;
    
        % get the most bright regions of the image
        int_thres = 0.26*max(max( images{i}));
        int_image{end+1} = images{i} > int_thres;
    
        % compute the final binary image by combining 
        % high 'activity' with high intensity
        bin_image{end+1} = log_image{i} .* int_image{i};
    
        % apply morphological dilation to connect distonnected components
        strel_size = round(0.01*max(size(imgs{i})));        % structuring element for morphological dilation
        dilated_image{end+1} = imdilate( bin_image{i}, strel('disk',strel_size));
    
        % do some measurements to eliminate small objects
        measurements{i} = regionprops( logical( dilated_image{i}),'Area','BoundingBox');
        for m=1:length(measurements{i})
            if measurements{i}(m).Area < 0.05*numel( dilated_image{i})
                dilated_image{i}( round(measurements{i}(m).BoundingBox(2):measurements{i}(m).BoundingBox(4)+measurements{i}(m).BoundingBox(2)),...
                    round(measurements{i}(m).BoundingBox(1):measurements{i}(m).BoundingBox(3)+measurements{i}(m).BoundingBox(1))) = 0;
            end
        end
        % make sure the dilated image is the same size with the original
        dilated_image{i} = dilated_image{i}(1:size(imgs{i},1),1:size(imgs{i},2));
        % compute the bounding box
        [y,x] = find( dilated_image{i});
        if isempty( y)
            box{end+1}=[];
        else
            box{end+1} = [ min(x) min(y) max(x)-min(x)+1 max(y)-min(y)+1];
        end
    end 
    
    %%% additional code to display things
    for i=1:num,
        figure;
        subplot(121);
        colormap gray;
        imshow( imgs{i});
        if ~isempty(box{i})
            hold on;
            rr = rectangle( 'position', box{i});
            set( rr, 'EdgeColor', 'r');
            hold off;
        end
        subplot(122);
        imshow( imgs{i}.*uint8(repmat(dilated_image{i},[1 1 3])));
    end
    
    %清除所有内容
    清楚的
    包装;
    全部关闭;
    关闭所有隐藏的文件;
    现在抽;
    clc;
    %初始化
    ims=dir('./*.jpg');
    imgs={};
    图像={};
    模糊_图像={};
    log_image={};
    放大的_图像={};
    int_image={};
    bin_image={};
    测量值={};
    box={};
    num=长度(ims);
    thres_div=3;
    对于i=1:num,
    %加载原始图像
    imgs{end+1}=imread(ims(i).name);
    %转换为灰度
    图像{end+1}=rgb2gray(imgs{i});
    %应用拉普拉斯滤波和启发式硬阈值
    val_thres=(max(max(images{i}))/thres_div;
    log_image{end+1}=imfilter(image{i},fspecial('log'))>val_thres;
    %获取图像中最亮的区域
    int_thres=0.26*max(max(images{i}));
    int_image{end+1}=图像{i}>int_-thres;
    %通过组合计算最终的二值图像
    %高强度的高“活动”
    bin_image{end+1}=log_image{i}.*int_image{i};
    %应用形态扩张来连接断开的组件
    strel_size=round(0.01*max(size(imgs{i}));%形态扩张的结构元素
    扩展图像{end+1}=imdeplate(bin_图像{i},strel('disk',strel_size));
    %进行一些测量以消除小物体
    测量值{i}=区域属性(逻辑(放大的{i})、‘区域’、‘边界框’;
    对于m=1:长度(测量值{i})
    如果测量值{i}(m).面积<0.05*numel(放大图像{i})
    扩展的_图像{i}(圆形(测量值{i}(m).包围盒(2):测量值{i}(m).包围盒(4)+测量值{i}(m).包围盒(2)),。。。
    圆形(度量值{i}(m).包围盒(1):度量值{i}(m).包围盒(3)+度量值{i}(m).包围盒(1))=0;
    结束
    结束
    %确保放大后的图像与原始图像大小相同
    
    R=double(Irgb(:,:,1));
    G=double(Irgb(:,:,2));
    B=double(Irgb(:,:,3));
    I0 = (3*R + max(G,B)-min(G,B))/2;
    
    I0_copy = zeros(size(I0));
    for i = 2 : size(I0,1) - 1
        for j = 2 : size(I0,2) - 1
            tmp = I0(i-1:i+1,j-1:j+1) >= I0(i,j);
            I0_copy(i,j) = mean(mean(tmp.*I0(i-1:i+1,j-1:j+1))) - ...
                mean(mean(~tmp.*I0(i-1:i+1,j-1:j+1))); % Contrast
        end
    end
    
    [centroids, idx] = runkMeans(X, initial_centroids, max_iters);
    mask=reshape(idx,img_size(1),img_size(2));
    
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    function [centroids, idx] = runkMeans(X, initial_centroids, ...
                                      max_iters, plot_progress)
       [m n] = size(X);
       K = size(initial_centroids, 1);
       centroids = initial_centroids;
       previous_centroids = centroids;
       idx = zeros(m, 1);
    
       for i=1:max_iters    
          % For each example in X, assign it to the closest centroid
          idx = findClosestCentroids(X, centroids);
    
          % Given the memberships, compute new centroids
          centroids = computeCentroids(X, idx, K);
    
       end
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    function idx = findClosestCentroids(X, centroids)
       K = size(centroids, 1);
       idx = zeros(size(X,1), 1);
       for xi = 1:size(X,1)
          x = X(xi, :);
          % Find closest centroid for x.
          best = Inf;
          for mui = 1:K
            mu = centroids(mui, :);
            d = dot(x - mu, x - mu);
            if d < best
               best = d;
               idx(xi) = mui;
            end
          end
       end 
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    function centroids = computeCentroids(X, idx, K)
       [m n] = size(X);
       centroids = zeros(K, n);
       for mui = 1:K
          centroids(mui, :) = sum(X(idx == mui, :)) / sum(idx == mui);
       end
    
    % clear everything
    clear;
    pack;
    close all;
    close all hidden;
    drawnow;
    clc;
    
    % initialization
    ims=dir('./*.jpg');
    num=length(ims);
    
    imgs={};
    hsvs={}; 
    masks={};
    dilated_images={};
    measurements={};
    boxs={};
    
    for i=1:num, 
        % load original image
        imgs{end+1} = imread(ims(i).name);
        flt_x_size = round(size(imgs{i},2)*0.005);
        flt_y_size = round(size(imgs{i},1)*0.005);
        flt = fspecial( 'average', max( flt_y_size, flt_x_size));
        imgs{i} = imfilter( imgs{i}, flt, 'same');
        % convert to HSV colorspace
        hsvs{end+1} = rgb2hsv(imgs{i});
        % apply a hard thresholding and binary operation to construct the mask
        masks{end+1} = medfilt2( ~(hsvs{i}(:,:,1)>(210/360) & hsvs{i}(:,:,1)<(320/360))&hsvs{i}(:,:,3)>0.4);
        % apply morphological dilation to connect distonnected components
        strel_size = round(0.03*max(size(imgs{i})));        % structuring element for morphological dilation
        dilated_images{end+1} = imdilate( masks{i}, strel('disk',strel_size));
        % do some measurements to eliminate small objects
        measurements{i} = regionprops( dilated_images{i},'Perimeter','Area','BoundingBox'); 
        for m=1:length(measurements{i})
            if (measurements{i}(m).Area < 0.02*numel( dilated_images{i})) || (measurements{i}(m).BoundingBox(3)>1.2*measurements{i}(m).BoundingBox(4))
                dilated_images{i}( round(measurements{i}(m).BoundingBox(2):measurements{i}(m).BoundingBox(4)+measurements{i}(m).BoundingBox(2)),...
                    round(measurements{i}(m).BoundingBox(1):measurements{i}(m).BoundingBox(3)+measurements{i}(m).BoundingBox(1))) = 0;
            end
        end
        dilated_images{i} = dilated_images{i}(1:size(imgs{i},1),1:size(imgs{i},2));
        % compute the bounding box
        [y,x] = find( dilated_images{i});
        if isempty( y)
            boxs{end+1}=[];
        else
            boxs{end+1} = [ min(x) min(y) max(x)-min(x)+1 max(y)-min(y)+1];
        end
    
    end 
    
    %%% additional code to display things
    for i=1:num,
        figure;
        subplot(121);
        colormap gray;
        imshow( imgs{i});
        if ~isempty(boxs{i})
            hold on;
            rr = rectangle( 'position', boxs{i});
            set( rr, 'EdgeColor', 'r');
            hold off;
        end
        subplot(122);
        imshow( imgs{i}.*uint8(repmat(dilated_images{i},[1 1 3])));
    end
    
    % clear everything
    clear;
    pack;
    close all;
    close all hidden;
    drawnow;
    clc;
    
    % initialization
    ims=dir('./*.jpg');
    imgs={};
    images={}; 
    blur_images={}; 
    log_image={}; 
    dilated_image={};
    int_image={};
    back_image={};
    bin_image={};
    measurements={};
    box={};
    num=length(ims);
    thres_div = 3;
    
    for i=1:num, 
        % load original image
        imgs{end+1}=imread(ims(i).name);
    
        % convert to HSV colorspace
        images{end+1}=rgb2hsv(imgs{i});
    
        % apply laplacian filtering and heuristic hard thresholding
        val_thres = (max(max(images{i}(:,:,3)))/thres_div);
        log_image{end+1} = imfilter( images{i}(:,:,3),fspecial('log')) > val_thres;
    
        % get the most bright regions of the image
        int_thres = 0.26*max(max( images{i}(:,:,3)));
        int_image{end+1} = images{i}(:,:,3) > int_thres;
    
        % get the most probable background regions of the image
        back_image{end+1} = images{i}(:,:,1)>(150/360) & images{i}(:,:,1)<(320/360) & images{i}(:,:,3)<0.5;
    
        % compute the final binary image by combining 
        % high 'activity' with high intensity
        bin_image{end+1} = logical( log_image{i}) & logical( int_image{i}) & ~logical( back_image{i});
    
        % apply morphological dilation to connect distonnected components
        strel_size = round(0.01*max(size(imgs{i})));        % structuring element for morphological dilation
        dilated_image{end+1} = imdilate( bin_image{i}, strel('disk',strel_size));
    
        % do some measurements to eliminate small objects
        measurements{i} = regionprops( logical( dilated_image{i}),'Area','BoundingBox');
    
        % iterative enlargement of the structuring element for better connectivity
        while length(measurements{i})>14 && strel_size<(min(size(imgs{i}(:,:,1)))/2),
            strel_size = round( 1.5 * strel_size);
            dilated_image{i} = imdilate( bin_image{i}, strel('disk',strel_size));
            measurements{i} = regionprops( logical( dilated_image{i}),'Area','BoundingBox');
        end
    
        for m=1:length(measurements{i})
            if measurements{i}(m).Area < 0.05*numel( dilated_image{i})
                dilated_image{i}( round(measurements{i}(m).BoundingBox(2):measurements{i}(m).BoundingBox(4)+measurements{i}(m).BoundingBox(2)),...
                    round(measurements{i}(m).BoundingBox(1):measurements{i}(m).BoundingBox(3)+measurements{i}(m).BoundingBox(1))) = 0;
            end
        end
        % make sure the dilated image is the same size with the original
        dilated_image{i} = dilated_image{i}(1:size(imgs{i},1),1:size(imgs{i},2));
        % compute the bounding box
        [y,x] = find( dilated_image{i});
        if isempty( y)
            box{end+1}=[];
        else
            box{end+1} = [ min(x) min(y) max(x)-min(x)+1 max(y)-min(y)+1];
        end
    end 
    
    %%% additional code to display things
    for i=1:num,
        figure;
        subplot(121);
        colormap gray;
        imshow( imgs{i});
        if ~isempty(box{i})
            hold on;
            rr = rectangle( 'position', box{i});
            set( rr, 'EdgeColor', 'r');
            hold off;
        end
        subplot(122);
        imshow( imgs{i}.*uint8(repmat(dilated_image{i},[1 1 3])));
    end
    
    from PIL import Image
    import numpy as np
    import scipy as sp
    import matplotlib.colors as colors
    from sklearn.cluster import DBSCAN
    from math import ceil, sqrt
    
    """
    Inputs:
    
        rgbimg:         [M,N,3] numpy array containing (uint, 0-255) color image
    
        hueleftthr:     Scalar constant to select maximum allowed hue in the
                        yellow-green region
    
        huerightthr:    Scalar constant to select minimum allowed hue in the
                        blue-purple region
    
        satthr:         Scalar constant to select minimum allowed saturation
    
        valthr:         Scalar constant to select minimum allowed value
    
        monothr:        Scalar constant to select minimum allowed monochrome
                        brightness
    
        maxpoints:      Scalar constant maximum number of pixels to forward to
                        the DBSCAN clustering algorithm
    
        proxthresh:     Proximity threshold to use for DBSCAN, as a fraction of
                        the diagonal size of the image
    
    Outputs:
    
        borderseg:      [K,2,2] Nested list containing K pairs of x- and y- pixel
                        values for drawing the tree border
    
        X:              [P,2] List of pixels that passed the threshold step
    
        labels:         [Q,2] List of cluster labels for points in Xslice (see
                        below)
    
        Xslice:         [Q,2] Reduced list of pixels to be passed to DBSCAN
    
    """
    
    def findtree(rgbimg, hueleftthr=0.2, huerightthr=0.95, satthr=0.7, 
                 valthr=0.7, monothr=220, maxpoints=5000, proxthresh=0.04):
    
        # Convert rgb image to monochrome for
        gryimg = np.asarray(Image.fromarray(rgbimg).convert('L'))
        # Convert rgb image (uint, 0-255) to hsv (float, 0.0-1.0)
        hsvimg = colors.rgb_to_hsv(rgbimg.astype(float)/255)
    
        # Initialize binary thresholded image
        binimg = np.zeros((rgbimg.shape[0], rgbimg.shape[1]))
        # Find pixels with hue<0.2 or hue>0.95 (red or yellow) and saturation/value
        # both greater than 0.7 (saturated and bright)--tends to coincide with
        # ornamental lights on trees in some of the images
        boolidx = np.logical_and(
                    np.logical_and(
                      np.logical_or((hsvimg[:,:,0] < hueleftthr),
                                    (hsvimg[:,:,0] > huerightthr)),
                                    (hsvimg[:,:,1] > satthr)),
                                    (hsvimg[:,:,2] > valthr))
        # Find pixels that meet hsv criterion
        binimg[np.where(boolidx)] = 255
        # Add pixels that meet grayscale brightness criterion
        binimg[np.where(gryimg > monothr)] = 255
    
        # Prepare thresholded points for DBSCAN clustering algorithm
        X = np.transpose(np.where(binimg == 255))
        Xslice = X
        nsample = len(Xslice)
        if nsample > maxpoints:
            # Make sure number of points does not exceed DBSCAN maximum capacity
            Xslice = X[range(0,nsample,int(ceil(float(nsample)/maxpoints)))]
    
        # Translate DBSCAN proximity threshold to units of pixels and run DBSCAN
        pixproxthr = proxthresh * sqrt(binimg.shape[0]**2 + binimg.shape[1]**2)
        db = DBSCAN(eps=pixproxthr, min_samples=10).fit(Xslice)
        labels = db.labels_.astype(int)
    
        # Find the largest cluster (i.e., with most points) and obtain convex hull   
        unique_labels = set(labels)
        maxclustpt = 0
        for k in unique_labels:
            class_members = [index[0] for index in np.argwhere(labels == k)]
            if len(class_members) > maxclustpt:
                points = Xslice[class_members]
                hull = sp.spatial.ConvexHull(points)
                maxclustpt = len(class_members)
                borderseg = [[points[simplex,0], points[simplex,1]] for simplex
                              in hull.simplices]
    
        return borderseg, X, labels, Xslice
    
    #!/usr/bin/env python
    
    from PIL import Image
    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.cm as cm
    from findtree import findtree
    
    # Image files to process
    fname = ['nmzwj.png', 'aVZhC.png', '2K9EF.png',
             'YowlH.png', '2y4o5.png', 'FWhSP.png']
    
    # Initialize figures
    fgsz = (16,7)        
    figthresh = plt.figure(figsize=fgsz, facecolor='w')
    figclust  = plt.figure(figsize=fgsz, facecolor='w')
    figcltwo  = plt.figure(figsize=fgsz, facecolor='w')
    figborder = plt.figure(figsize=fgsz, facecolor='w')
    figthresh.canvas.set_window_title('Thresholded HSV and Monochrome Brightness')
    figclust.canvas.set_window_title('DBSCAN Clusters (Raw Pixel Output)')
    figcltwo.canvas.set_window_title('DBSCAN Clusters (Slightly Dilated for Display)')
    figborder.canvas.set_window_title('Trees with Borders')
    
    for ii, name in zip(range(len(fname)), fname):
        # Open the file and convert to rgb image
        rgbimg = np.asarray(Image.open(name))
    
        # Get the tree borders as well as a bunch of other intermediate values
        # that will be used to illustrate how the algorithm works
        borderseg, X, labels, Xslice = findtree(rgbimg)
    
        # Display thresholded images
        axthresh = figthresh.add_subplot(2,3,ii+1)
        axthresh.set_xticks([])
        axthresh.set_yticks([])
        binimg = np.zeros((rgbimg.shape[0], rgbimg.shape[1]))
        for v, h in X:
            binimg[v,h] = 255
        axthresh.imshow(binimg, interpolation='nearest', cmap='Greys')
    
        # Display color-coded clusters
        axclust = figclust.add_subplot(2,3,ii+1) # Raw version
        axclust.set_xticks([])
        axclust.set_yticks([])
        axcltwo = figcltwo.add_subplot(2,3,ii+1) # Dilated slightly for display only
        axcltwo.set_xticks([])
        axcltwo.set_yticks([])
        axcltwo.imshow(binimg, interpolation='nearest', cmap='Greys')
        clustimg = np.ones(rgbimg.shape)    
        unique_labels = set(labels)
        # Generate a unique color for each cluster 
        plcol = cm.rainbow_r(np.linspace(0, 1, len(unique_labels)))
        for lbl, pix in zip(labels, Xslice):
            for col, unqlbl in zip(plcol, unique_labels):
                if lbl == unqlbl:
                    # Cluster label of -1 indicates no cluster membership;
                    # override default color with black
                    if lbl == -1:
                        col = [0.0, 0.0, 0.0, 1.0]
                    # Raw version
                    for ij in range(3):
                        clustimg[pix[0],pix[1],ij] = col[ij]
                    # Dilated just for display
                    axcltwo.plot(pix[1], pix[0], 'o', markerfacecolor=col, 
                        markersize=1, markeredgecolor=col)
        axclust.imshow(clustimg)
        axcltwo.set_xlim(0, binimg.shape[1]-1)
        axcltwo.set_ylim(binimg.shape[0], -1)
    
        # Plot original images with read borders around the trees
        axborder = figborder.add_subplot(2,3,ii+1)
        axborder.set_axis_off()
        axborder.imshow(rgbimg, interpolation='nearest')
        for vseg, hseg in borderseg:
            axborder.plot(hseg, vseg, 'r-', lw=3)
        axborder.set_xlim(0, binimg.shape[1]-1)
        axborder.set_ylim(binimg.shape[0], -1)
    
    plt.show()
    
    <?php
    
    ini_set('memory_limit', '1024M');
    
    header("Content-type: image/png");
    
    $chosenImage = 6;
    
    switch($chosenImage){
        case 1:
            $inputImage     = imagecreatefromjpeg("nmzwj.jpg");
            break;
        case 2:
            $inputImage     = imagecreatefromjpeg("2y4o5.jpg");
            break;
        case 3:
            $inputImage     = imagecreatefromjpeg("YowlH.jpg");
            break;
        case 4:
            $inputImage     = imagecreatefromjpeg("2K9Ef.jpg");
            break;
        case 5:
            $inputImage     = imagecreatefromjpeg("aVZhC.jpg");
            break;
        case 6:
            $inputImage     = imagecreatefromjpeg("FWhSP.jpg");
            break;
        case 7:
            $inputImage     = imagecreatefromjpeg("roemerberg.jpg");
            break;
        default:
            exit();
    }
    
    // Process the loaded image
    
    $topNspots = processImage($inputImage);
    
    imagejpeg($inputImage);
    imagedestroy($inputImage);
    
    // Here be functions
    
    function processImage($image) {
        $orange = imagecolorallocate($image, 220, 210, 60);
        $black = imagecolorallocate($image, 0, 0, 0);
        $red = imagecolorallocate($image, 255, 0, 0);
    
        $maxX = imagesx($image)-1;
        $maxY = imagesy($image)-1;
    
        // Parameters
        $spread = 1; // Number of pixels to each direction that will be added up
        $topPositions = 80; // Number of (brightest) lights taken into account
        $minLightDistance = round(min(array($maxX, $maxY)) / 30); // Minimum number of pixels between the brigtests lights
        $searchYperX = 5; // spread of the "search beam" from the median point to the top
    
        $renderStage = 3; // 1 to 3; exits the process early
    
    
        // STAGE 1
        // Calculate the brightness of each pixel (R+G+B)
    
        $maxBrightness = 0;
        $stage1array = array();
    
        for($row = 0; $row <= $maxY; $row++) {
    
            $stage1array[$row] = array();
    
            for($col = 0; $col <= $maxX; $col++) {
    
                $rgb = imagecolorat($image, $col, $row);
                $brightness = getBrightnessFromRgb($rgb);
                $stage1array[$row][$col] = $brightness;
    
                if($renderStage == 1){
                    $brightnessToGrey = round($brightness / 765 * 256);
                    $greyRgb = imagecolorallocate($image, $brightnessToGrey, $brightnessToGrey, $brightnessToGrey);
                    imagesetpixel($image, $col, $row, $greyRgb);
                }
    
                if($brightness > $maxBrightness) {
                    $maxBrightness = $brightness;
                    if($renderStage == 1){
                        imagesetpixel($image, $col, $row, $red);
                    }
                }
            }
        }
        if($renderStage == 1) {
            return;
        }
    
    
        // STAGE 2
        // Add up brightness of neighbouring pixels
    
        $stage2array = array();
        $maxStage2 = 0;
    
        for($row = 0; $row <= $maxY; $row++) {
            $stage2array[$row] = array();
    
            for($col = 0; $col <= $maxX; $col++) {
                if(!isset($stage2array[$row][$col])) $stage2array[$row][$col] = 0;
    
                // Look around the current pixel, add brightness
                for($y = $row-$spread; $y <= $row+$spread; $y++) {
                    for($x = $col-$spread; $x <= $col+$spread; $x++) {
    
                        // Don't read values from outside the image
                        if($x >= 0 && $x <= $maxX && $y >= 0 && $y <= $maxY){
                            $stage2array[$row][$col] += $stage1array[$y][$x]+10;
                        }
                    }
                }
    
                $stage2value = $stage2array[$row][$col];
                if($stage2value > $maxStage2) {
                    $maxStage2 = $stage2value;
                }
            }
        }
    
        if($renderStage >= 2){
            // Paint the accumulated light, dimmed by the maximum value from stage 2
            for($row = 0; $row <= $maxY; $row++) {
                for($col = 0; $col <= $maxX; $col++) {
                    $brightness = round($stage2array[$row][$col] / $maxStage2 * 255);
                    $greyRgb = imagecolorallocate($image, $brightness, $brightness, $brightness);
                    imagesetpixel($image, $col, $row, $greyRgb);
                }
            }
        }
    
        if($renderStage == 2) {
            return;
        }
    
    
        // STAGE 3
    
        // Create a ranking of bright spots (like "Top 20")
        $topN = array();
    
        for($row = 0; $row <= $maxY; $row++) {
            for($col = 0; $col <= $maxX; $col++) {
    
                $stage2Brightness = $stage2array[$row][$col];
                $topN[$col.":".$row] = $stage2Brightness;
            }
        }
        arsort($topN);
    
        $topNused = array();
        $topPositionCountdown = $topPositions;
    
        if($renderStage == 3){
            foreach ($topN as $key => $val) {
                if($topPositionCountdown <= 0){
                    break;
                }
    
                $position = explode(":", $key);
    
                foreach($topNused as $usedPosition => $usedValue) {
                    $usedPosition = explode(":", $usedPosition);
                    $distance = abs($usedPosition[0] - $position[0]) + abs($usedPosition[1] - $position[1]);
                    if($distance < $minLightDistance) {
                        continue 2;
                    }
                }
    
                $topNused[$key] = $val;
    
                paintCrosshair($image, $position[0], $position[1], $red, 2);
    
                $topPositionCountdown--;
    
            }
        }
    
    
        // STAGE 4
        // Median of all Top N lights
        $topNxValues = array();
        $topNyValues = array();
    
        foreach ($topNused as $key => $val) {
            $position = explode(":", $key);
            array_push($topNxValues, $position[0]);
            array_push($topNyValues, $position[1]);
        }
    
        $medianXvalue = round(calculate_median($topNxValues));
        $medianYvalue = round(calculate_median($topNyValues));
        paintCrosshair($image, $medianXvalue, $medianYvalue, $red, 15);
    
    
        // STAGE 5
        // Find treetop
    
        $filename = 'debug.log';
        $handle = fopen($filename, "w");
        fwrite($handle, "\n\n STAGE 5");
    
        $treetopX = $medianXvalue;
        $treetopY = $medianYvalue;
    
        $searchXmin = $medianXvalue;
        $searchXmax = $medianXvalue;
    
        $width = 0;
        for($y = $medianYvalue; $y >= 0; $y--) {
            fwrite($handle, "\nAt y = ".$y);
    
            if(($y % $searchYperX) == 0) { // Modulo
                $width++;
                $searchXmin = $medianXvalue - $width;
                $searchXmax = $medianXvalue + $width;
                imagesetpixel($image, $searchXmin, $y, $red);
                imagesetpixel($image, $searchXmax, $y, $red);
            }
    
            foreach ($topNused as $key => $val) {
                $position = explode(":", $key); // "x:y"
    
                if($position[1] != $y){
                    continue;
                }
    
                if($position[0] >= $searchXmin && $position[0] <= $searchXmax){
                    $treetopX = $position[0];
                    $treetopY = $y;
                }
            }
    
        }
    
        paintCrosshair($image, $treetopX, $treetopY, $red, 5);
    
    
        // STAGE 6
        // Find tree sides
        fwrite($handle, "\n\n STAGE 6");
    
        $treesideAngle = 60; // The extremely "fat" end of a christmas tree
        $treeBottomY = $treetopY;
    
        $topPositionsExcluded = 0;
        $xymultiplier = 0;
        while(($topPositionsExcluded < ($topPositions / 5)) && $treesideAngle >= 1){
            fwrite($handle, "\n\nWe're at angle ".$treesideAngle);
            $xymultiplier = sin(deg2rad($treesideAngle));
            fwrite($handle, "\nMultiplier: ".$xymultiplier);
    
            $topPositionsExcluded = 0;
            foreach ($topNused as $key => $val) {
                $position = explode(":", $key);
                fwrite($handle, "\nAt position ".$key);
    
                if($position[1] > $treeBottomY) {
                    $treeBottomY = $position[1];
                }
    
                // Lights above the tree are outside of it, but don't matter
                if($position[1] < $treetopY){
                    $topPositionsExcluded++;
                    fwrite($handle, "\nTOO HIGH");
                    continue;
                }
    
                // Top light will generate division by zero
                if($treetopY-$position[1] == 0) {
                    fwrite($handle, "\nDIVISION BY ZERO");
                    continue;
                }
    
                // Lights left end right of it are also not inside
                fwrite($handle, "\nLight position factor: ".(abs($treetopX-$position[0]) / abs($treetopY-$position[1])));
                if((abs($treetopX-$position[0]) / abs($treetopY-$position[1])) > $xymultiplier){
                    $topPositionsExcluded++;
                    fwrite($handle, "\n --- Outside tree ---");
                }
            }
    
            $treesideAngle--;
        }
        fclose($handle);
    
        // Paint tree's outline
        $treeHeight = abs($treetopY-$treeBottomY);
        $treeBottomLeft = 0;
        $treeBottomRight = 0;
        $previousState = false; // line has not started; assumes the tree does not "leave"^^
    
        for($x = 0; $x <= $maxX; $x++){
            if(abs($treetopX-$x) != 0 && abs($treetopX-$x) / $treeHeight > $xymultiplier){
                if($previousState == true){
                    $treeBottomRight = $x;
                    $previousState = false;
                }
                continue;
            }
            imagesetpixel($image, $x, $treeBottomY, $red);
            if($previousState == false){
                $treeBottomLeft = $x;
                $previousState = true;
            }
        }
        imageline($image, $treeBottomLeft, $treeBottomY, $treetopX, $treetopY, $red);
        imageline($image, $treeBottomRight, $treeBottomY, $treetopX, $treetopY, $red);
    
    
        // Print out some parameters
    
        $string = "Min dist: ".$minLightDistance." | Tree angle: ".$treesideAngle." deg | Tree bottom: ".$treeBottomY;
    
        $px     = (imagesx($image) - 6.5 * strlen($string)) / 2;
        imagestring($image, 2, $px, 5, $string, $orange);
    
        return $topN;
    }
    
    /**
     * Returns values from 0 to 765
     */
    function getBrightnessFromRgb($rgb) {
        $r = ($rgb >> 16) & 0xFF;
        $g = ($rgb >> 8) & 0xFF;
        $b = $rgb & 0xFF;
    
        return $r+$r+$b;
    }
    
    function paintCrosshair($image, $posX, $posY, $color, $size=5) {
        for($x = $posX-$size; $x <= $posX+$size; $x++) {
            if($x>=0 && $x < imagesx($image)){
                imagesetpixel($image, $x, $posY, $color);
            }
        }
        for($y = $posY-$size; $y <= $posY+$size; $y++) {
            if($y>=0 && $y < imagesy($image)){
                imagesetpixel($image, $posX, $y, $color);
            }
        }
    }
    
    // From http://www.mdj.us/web-development/php-programming/calculating-the-median-average-values-of-an-array-with-php/
    function calculate_median($arr) {
        sort($arr);
        $count = count($arr); //total numbers in array
        $middleval = floor(($count-1)/2); // find the middle value, or the lowest middle value
        if($count % 2) { // odd number, middle is the median
            $median = $arr[$middleval];
        } else { // even number, calculate avg of 2 medians
            $low = $arr[$middleval];
            $high = $arr[$middleval+1];
            $median = (($low+$high)/2);
        }
        return $median;
    }
    
    
    ?>
    
    #include "opencv2/highgui/highgui.hpp"
    #include "opencv2/opencv.hpp"
    #include <algorithm>
    using namespace cv;
    
    int main()
    {
    
        string images[6] = {"..\\1.png","..\\2.png","..\\3.png","..\\4.png","..\\5.png","..\\6.png"};
    
        for(int i = 0; i < 6; ++i)
        {
            Mat img, thresholded, tdilated, tmp, tmp1;
            vector<Mat> channels(3);
    
            img = imread(images[i]);
            split(img, channels);
            threshold( channels[2], thresholded, 149, 255, THRESH_BINARY);                      //prepare ROI - threshold
            dilate( thresholded, tdilated,  getStructuringElement( MORPH_RECT, Size(22,22) ) ); //prepare ROI - dilate
            Canny( channels[2], tmp, 75, 125, 3, true );    //Canny edge detection
            multiply( tmp, tdilated, tmp1 );    // set ROI
    
            dilate( tmp1, tmp, getStructuringElement( MORPH_RECT, Size(20,16) ) ); // dilate
            erode( tmp, tmp1, getStructuringElement( MORPH_RECT, Size(36,36) ) ); // erode
    
            vector<vector<Point> > contours, contours1(1);
            vector<Point> convex;
            vector<Vec4i> hierarchy;
            findContours( tmp1, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
    
            //get element of maximum area
            //int bestID = std::max_element( contours.begin(), contours.end(), 
            //  []( const vector<Point>& A, const vector<Point>& B ) { return contourArea(A) < contourArea(B); } ) - contours.begin();
    
                int bestID = 0;
            int bestArea = contourArea( contours[0] );
            for( int i = 1; i < contours.size(); ++i )
            {
                int area = contourArea( contours[i] );
                if( area > bestArea )
                {
                    bestArea  = area;
                    bestID = i;
                }
            }
    
            convexHull( contours[bestID], contours1[0] ); 
            drawContours( img, contours1, 0, Scalar( 100, 100, 255 ), img.rows / 100, 8, hierarchy, 0, Point() );
    
            imshow("image", img );
            waitKey(0);
        }
    
    
        return 0;
    }
    
    import numpy as np
    import cv2
    import copy
    
    
    def findTree(image,num):
        im = cv2.imread(image)
        im = cv2.resize(im, (400,250))
        gray = cv2.cvtColor(im, cv2.COLOR_RGB2GRAY)
        imf = copy.deepcopy(im)
    
        b,g,r = cv2.split(im)
        minR = 200
        _,thresh = cv2.threshold(r,minR,255,0)
        kernel = np.ones((25,5))
        dst = cv2.morphologyEx(thresh, cv2.MORPH_GRADIENT, kernel)
        dst = cv2.morphologyEx(dst, cv2.MORPH_CLOSE, kernel)
    
        contours = cv2.findContours(dst,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)[0]
        cv2.drawContours(im, contours,-1, (0,255,0), 1)
    
        maxI = 0
        for i in range(len(contours)):
            if len(contours[maxI]) < len(contours[i]):
                maxI = i
    
        img = copy.deepcopy(r)
        cv2.polylines(img,[contours[maxI]],True,(255,255,255),3)
        imf[:,:,2] = img
    
        cv2.imshow(str(num), imf)
    
    def main():
        findTree('tree.jpg',1)
        findTree('tree2.jpg',2)
        findTree('tree3.jpg',3)
        findTree('tree4.jpg',4)
        findTree('tree5.jpg',5)
        findTree('tree6.jpg',6)
    
        cv2.waitKey(0)
        cv2.destroyAllWindows()
    
    if __name__ == "__main__":
        main()