I\'m developing a shape identification project using JavaCV and I have found some OpenCV code to identify U shapes in a particular image. I have tried to convert it into JavaCV
This code work for me and I just put cvSeq=cvSeq.h_next(); line in to the program and remove the for loop add while loop for thet.
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);
}
}
Check your type promotions, e.g.:
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). Otherwise, as in this case, it is an integer division. (Note that the original code has promotion to float
as well.)
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!
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.
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. 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.
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:
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
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.