[英]opencv/javacv: How to iterate over contours for shape identification?
我正在使用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()
這是預期的產出
這是轉換后的代碼:
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);
}
}
這是我得到的輸出。 有人可以幫我解決這個問題嗎?
編輯:這是最有趣的發現 - 我認為你沒有在輪廓中正確迭代 - 你應該做的事情如下:
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
可能導致完全不同的灰色圖像。 我會在兩個程序上添加一些調試步驟來保存臨時灰度圖像,並將它們與x,y,w
和h
的值進行比較(10 < (w/h) || (w/h) < 0.1)
是真的。
另一件事是在java解決方案中使用CV_RETR_CCOMP
來獲取輪廓,並在python解決方案中根據文檔使用CV_RETR_LIST
:
CV_RETR_LIST檢索所有輪廓而不建立任何層次關系CV_RETR_CCOMP檢索所有輪廓並將它們組織成兩級層次結構:頂層是組件的外部邊界,第二層是孔的邊界。 如果在連接組件的孔內有另一個輪廓,它仍然會被放在頂層
所以首先我要仔細檢查兩個程序中的所有cv參數是否相同,然后我會添加調試步驟以查看中間變量包含相同的數據。
檢查您的類型促銷,例如:
if (10 < (w/h) || (w/h) < 0.1){
..非常可疑。 要獲得浮點除法,一個(或兩個)操作數必須至少是一個float
(同樣是雙重除法的double
float
數)。 否則,如在這種情況下,它是整數除法。 (請注意, 原始代碼也有促進float
。)
例如:
float ratio = (float)w/h; // (float / int) => (float / float) -> float
if (10 < ratio || ratio < 0.1 ) {
(雖然我不確定這是否是這個問題。)
快樂的編碼!
這段代碼對我有用 ,我只是把cvSeq = cvSeq.h_next(); 進入程序並刪除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.