简体   繁体   English

opencv / javacv:如何迭代轮廓以进行形状识别?

[英]opencv/javacv: How to iterate over contours for shape identification?

I'm developing a shape identification project using JavaCV and I have found some OpenCV code to identify U shapes in a particular image. 我正在使用JavaCV开发一个形状识别项目,我发现了一些OpenCV代码来识别特定图像中的U形状。 I have tried to convert it into JavaCV but it doesn't give the same output. 我试图将其转换为JavaCV,但它没有提供相同的输出。 Can you please help me to convert this OpenCV code into JavaCV? 你能帮我把这个OpenCV代码转换成JavaCV吗?

This is the OpenCV code: 这是OpenCV代码:

import cv2
import numpy as np

img = cv2.imread('sofud.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray,127,255,1)
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)

for cnt in contours:
    x,y,w,h = cv2.boundingRect(cnt)
    if 10 < w/float(h) or w/float(h) < 0.1:
        cv2.rectangle(img,(x,y),(x+w,y+h),(0,0,255),2)

cv2.imshow('res',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

This is the expected output 这是预期的产出

在此输入图像描述

This is the converted code: 这是转换后的代码:

import com.googlecode.javacpp.Loader;
import com.googlecode.javacv.CanvasFrame;
import static com.googlecode.javacpp.Loader.*;
import static com.googlecode.javacv.cpp.opencv_core.*;
import static com.googlecode.javacv.cpp.opencv_imgproc.*;
import static com.googlecode.javacv.cpp.opencv_highgui.*;
import java.io.File;
import javax.swing.JFileChooser;

public class TestBeam {
    public static void main(String[] args) {
        CvMemStorage storage=CvMemStorage.create();
        CvSeq squares = new CvContour();
        squares = cvCreateSeq(0, sizeof(CvContour.class), sizeof(CvSeq.class), storage);
        JFileChooser f=new JFileChooser();
        int result=f.showOpenDialog(f);//show dialog box to choose files
            File myfile=null;
            String path="";
        if(result==0){
            myfile=f.getSelectedFile();//selected file taken to myfile
            path=myfile.getAbsolutePath();//get the path of the file
        }
        IplImage src = cvLoadImage(path);//hear path is actual path to image
        IplImage grayImage    = IplImage.create(src.width(), src.height(), IPL_DEPTH_8U, 1);
        cvCvtColor(src, grayImage, CV_RGB2GRAY);
        cvThreshold(grayImage, grayImage, 127, 255, CV_THRESH_BINARY);
        CvSeq cvSeq=new CvSeq();
        CvMemStorage memory=CvMemStorage.create();
        cvFindContours(grayImage, memory, cvSeq, Loader.sizeof(CvContour.class), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
        System.out.println(cvSeq.total());
        for (int i = 0; i < cvSeq.total(); i++) {
            CvRect rect=cvBoundingRect(cvSeq, i);
            int x=rect.x(),y=rect.y(),h=rect.height(),w=rect.width();
            if (10 < (w/h) || (w/h) < 0.1){
                cvRectangle(src, cvPoint(x, y), cvPoint(x+w, y+h), CvScalar.RED, 1, CV_AA, 0);
                //cvSeqPush(squares, rect);
            }
        }
        CanvasFrame cnvs=new CanvasFrame("Beam");
        cnvs.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
        cnvs.showImage(src);
        //cvShowImage("Final ", src);

    }
}

This is the output that I got. 这是我得到的输出。 Please can someone help me to solve this problem ? 有人可以帮我解决这个问题吗?

在此输入图像描述

EDIT: Here is the most interesting finding - I think you are not iterating correctly through the contours - you should do something like: 编辑:这是最有趣的发现 - 我认为你没有在轮廓中正确迭代 - 你应该做的事情如下:

CvRect rect = cvBoundingRect(cvGetSeqElem(cvSeq, i),0); //python default?

Or: 要么:

// ... 
CvSeq contours = new CvSeq();
CvSeq ptr = new CvSeq();
CvRect rect = null;
// ...
cvFindContours(..., contours, ...);

for (ptr = contours; ptr != null; ptr = ptr.h_next()) {
    rect =  cvBoundingRect(ptr, 0);
    // ... Draw the box if meets criteria
}

First, I think pst is right regarding the calculation of the ratio - you have to cast the width to float. 首先,我认为pst对于比率的计算是正确的 - 你必须将宽度转换为浮动。

Secondly, I see that when you are making the gray image in python you use COLOR_BGR2GRAY and in java you are using CV_RGB2GRAY that could lead to a totally different gray picture. 其次,我看到当你在python中制作灰色图像时,你使用COLOR_BGR2GRAY而在java中,你使用CV_RGB2GRAY可能导致完全不同的灰色图像。 I would add some debug steps on both programs to save the temp gray images and compare them as also print outs for the values of x,y,w and h when (10 < (w/h) || (w/h) < 0.1) is true. 我会在两个程序上添加一些调试步骤来保存临时灰度图像,并将它们与x,y,wh的值进行比较(10 < (w/h) || (w/h) < 0.1)是真的。

Another thing is that in the java solution you use CV_RETR_CCOMP to get the contours and in the python solution you use CV_RETR_LIST according to the documentation: 另一件事是在java解决方案中使用CV_RETR_CCOMP来获取轮廓,并在python解决方案中根据文档使用CV_RETR_LIST

CV_RETR_LIST retrieves all of the contours without establishing any hierarchical relationships CV_RETR_CCOMP retrieves all of the contours and organizes them into a two-level hierarchy: on the top level are the external boundaries of the components, on the second level are the boundaries of the holes. CV_RETR_LIST检索所有轮廓而不建立任何层次关系CV_RETR_CCOMP检索所有轮廓并将它们组织成两级层次结构:顶层是组件的外部边界,第二层是孔的边界。 If inside a hole of a connected component there is another contour, it will still be put on the top level 如果在连接组件的孔内有另一个轮廓,它仍然会被放在顶层

So first I would double check that all cv's parameters in both programs are the same, then I would add debug steps to see that the intermediate variables contains the same data. 所以首先我要仔细检查两个程序中的所有cv参数是否相同,然后我会添加调试步骤以查看中间变量包含相同的数据。

Check your type promotions, eg: 检查您的类型促销,例如:

if (10 < (w/h) || (w/h) < 0.1){

.. is highly suspect. ..非常可疑。 To get a floating point division, one (or both) of the operands must at least be a float (and likewise a double for double division). 要获得浮点除法,一个(或两个)操作数必须至少是一个float (同样是双重除法的double float数)。 Otherwise, as in this case, it is an integer division. 否则,如在这种情况下,它是整数除法。 (Note that the original code has promotion to float as well.) (请注意, 原始代码也有促进float 。)

For instance: 例如:

 float ratio = (float)w/h; // (float / int) => (float / float) -> float
 if (10 < ratio || ratio < 0.1 ) { 

(Although I am unsure if this is the issue here.) (虽然我不确定这是否是这个问题。)

Happy coding! 快乐的编码!

This code work for me and I just put cvSeq=cvSeq.h_next(); 这段代码对我有用 ,我只是把cvSeq = cvSeq.h_next(); line in to the program and remove the for loop add while loop for thet. 进入程序并删除for循环添加while循环。

    package Beam;
    import com.googlecode.javacpp.Loader;
    import com.googlecode.javacv.CanvasFrame;
    import static com.googlecode.javacpp.Loader.*;
    import static com.googlecode.javacv.cpp.opencv_core.*;
    import static com.googlecode.javacv.cpp.opencv_imgproc.*;
    import static com.googlecode.javacv.cpp.opencv_highgui.*;
    import java.io.File;
    import javax.swing.JFileChooser;

    public class TestBeam2 {
        public static void main(String[] args) {
            JFileChooser f=new JFileChooser();
            int result=f.showOpenDialog(f);//show dialog box to choose files
                File myfile=null;
                String path="";
            if(result==0){
                myfile=f.getSelectedFile();//selected file taken to myfile
                path=myfile.getAbsolutePath();//get the path of the file
            }
            IplImage src = cvLoadImage(path);//hear path is actual path to image
            IplImage grayImage    = IplImage.create(src.width(), src.height(), IPL_DEPTH_8U, 1);
            cvCvtColor(src, grayImage, CV_RGB2GRAY);
            cvThreshold(grayImage, grayImage, 127, 255, CV_THRESH_BINARY);
            CvSeq cvSeq=new CvSeq();
            CvMemStorage memory=CvMemStorage.create();
            cvFindContours(grayImage, memory, cvSeq, Loader.sizeof(CvContour.class), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);

            while (cvSeq != null && !cvSeq.isNull()) {
                CvRect rect=cvBoundingRect(cvSeq, 0);
                int x=rect.x(),y=rect.y(),h=rect.height(),w=rect.width();
                if (10 < w/h || w/h < 0.1){
                    cvRectangle(src, cvPoint(x, y), cvPoint(x+w, y+h), CvScalar.RED, 1, CV_AA, 0);
                }
                cvSeq=cvSeq.h_next();
            }
            CanvasFrame cnvs=new CanvasFrame("Beam");
            cnvs.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
            cnvs.showImage(src);
            //cvShowImage("Final ", src);
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM