有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

我正在使用JavaCV开发一个形状识别项目,我发现了一些OpenCV代码来识别特定图像中的U形。我曾尝试将其转换为JavaCV,但它没有给出相同的输出。你能帮我把这个OpenCV代码转换成JavaCV吗

这是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()

这是预期产出

enter image description here

这是转换后的代码:

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);

    }
}

这是我得到的结果。有人能帮我解决这个问题吗

enter image description here


共 (2) 个答案

  1. # 1 楼答案

    编辑:以下是最有趣的发现- 我认为你没有正确地通过轮廓进行迭代——你应该这样做:

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

    或者:

    // ... 
    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
    }
    

    首先,我认为pst关于比率的计算是正确的——你必须将宽度转换为浮动

    其次,我发现在python中制作灰色图像时使用COLOR_BGR2GRAY,在java中使用CV_RGB2GRAY,这可能会产生完全不同的灰色图像。我会在两个程序上添加一些调试步骤,以保存临时灰度图像,并在(10 < (w/h) || (w/h) < 0.1)为真时,将它们作为x,y,wh值的打印输出进行比较

    另一件事是,在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. If inside a hole of a connected component there is another contour, it will still be put on the top level

    因此,首先我会仔细检查两个程序中所有cv的参数是否相同,然后我会添加调试步骤,以查看中间变量是否包含相同的数据

  2. # 2 楼答案

    检查您的类型促销,例如:

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

    。。他非常可疑。要得到一个浮点除法,其中一个(或两个)操作数必须至少是float(对于双除法也是double)。否则,与本例一样,它是一个整数除法。(请注意,原始的代码也可以升级到float。)

    例如:

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

    (尽管我不确定这是否是这里的问题。)

    编码快乐