Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenCv in Android: keypoint detection in images from file

I'm new to both OpenCv and StackOverflow, and almost new to Android programming so please excuse me if my question is stupid.

I am trying to match an image acquired from camera against some image files, to see which image file is more similar to the camera image. So I use DescriptorExtractor.compute to get the keypoints of the file image and the camera image with SURF (I also tried SIFT) in order to match them but... the method applied to the file image always returns an empty keypoint list, while if I use it on the camera image, I always get a non empty list (a hundred of points on average). What puzzles me most is that the even using the very same image, loaded from the camera first, and then from file, I get this behavior.

Could you please help me figure out what I'm doing wrong? Here is some test code (only for the file part, but I use the same method getKp to extract keypoints from camera as well).

public class HelloOpenCvActivity extends Activity {
    private static final int FILE_REQUEST = 400;
    /** Called when the activity is first created. */

    ImageView img;
    TextView txt;
    Bitmap logo;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        img = (ImageView) findViewById(R.id.image);
        txt = (TextView) findViewById(R.id.kp);

        img.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {
                chooseFile();               
            }
        });
    }

    private void chooseFile(){
        Intent fileIntent = new Intent(Intent.ACTION_GET_CONTENT);
        fileIntent.addCategory(Intent.CATEGORY_OPENABLE);
        fileIntent.setType("image/*");
        startActivityForResult(Intent.createChooser(fileIntent,"prova"), FILE_REQUEST); 
    }

    /*Quando ho il risultato della chiamata al file explorer, viene invocata questa callback */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
        if (requestCode == FILE_REQUEST) {  
            // obtain the filename
            Uri uri = data.getData();
            String filePath = null;
            if (uri != null) {
                if (uri.toString().startsWith("file:")) {
                    filePath = uri.getPath();
                } else { // uri.startsWith("content:")
                    Cursor c = getContentResolver().query(uri, null, null, null, null);
                    if (c != null && c.moveToFirst()) {
                        int id = c.getColumnIndex(Images.Media.DATA);
                        if (id != -1) {
                            filePath = c.getString(id);
                        }
                    }
                }
            }
            if (filePath != null) {
                logo = BitmapFactory.decodeFile(filePath);
                img.setImageBitmap(logo);
                txt.setText(""+getKp(logo).size());
            }
        }  
    }

    private List<KeyPoint> getKp(Bitmap bm){
        Mat image = Utils.bitmapToMat(bm);

        List<KeyPoint> kp = new ArrayList<KeyPoint>();
        FeatureDetector fd = FeatureDetector.create(FeatureDetector.SURF);
        fd.detect(image, kp);


        return kp;
    }

}

Thank you very much.

Ale

like image 879
Ale Avatar asked Nov 10 '11 12:11

Ale


1 Answers

After hours of research and headache ;-) I have found the problem. Images from camera and file can be both stored in bitmap objects, but their config (Bitmap.Config) is different: ARGB_8888 for camera images and RGB_565 for file ones. Changing bitmap configuration in file images to ARGB_8888 with Bitmap.copy method is the solution.

private List<KeyPoint> getKp(Bitmap bm){
    //scale bitmap (otherwise the program crashes due to memory lack)
    int MAX_DIM = 300;
    int w, h;       
    if (bm.getWidth() >= bm.getHeight()){
        w = MAX_DIM;
        h = bm.getHeight()*MAX_DIM/bm.getWidth();
    }
    else{
        h = MAX_DIM;
        w = bm.getWidth()*MAX_DIM/bm.getHeight();
    }
    bm = Bitmap.createScaledBitmap(bm, w, h, false);

    //change bitmap config <- THAT'S THE POINT!
    Bitmap img = bm.copy(Bitmap.Config.ARGB_8888, false);           

    Mat image = Utils.bitmapToMat(img);

    List<KeyPoint> kp = new ArrayList<KeyPoint>();
    FeatureDetector fd = FeatureDetector.create(FeatureDetector.SURF);
    fd.detect(image, kp);

    return kp;
}

Hope this can help anybody who runs into the same issue. :-)

like image 78
Ale Avatar answered Nov 11 '22 11:11

Ale