6 votes

OpenCv sous Android : détection de points clés dans les images à partir d'un fichier

Je suis nouveau sur OpenCv et StackOverflow, et presque nouveau dans la programmation Android, alors excusez-moi si ma question est stupide.

J'essaie de faire correspondre une image acquise à partir d'une caméra à certains fichiers d'image, afin de voir quel fichier d'image est le plus similaire à l'image de la caméra. J'utilise donc DescriptorExtractor.compute pour obtenir les points clés de l'image du fichier et de l'image de la caméra avec SURF (j'ai aussi essayé SIFT) afin de les faire correspondre mais... la méthode appliquée à l'image du fichier renvoie toujours une liste de points clés vide, alors que si je l'utilise sur l'image de la caméra, j'obtiens toujours une liste non vide (une centaine de points en moyenne). Ce qui m'intrigue le plus, c'est que même en utilisant la même image, chargée d'abord depuis la caméra, puis depuis le fichier, j'obtiens ce comportement.

Pourriez-vous m'aider à comprendre ce que je fais mal ? Voici un peu de code de test (seulement pour la partie fichier, mais j'utilise la même méthode getKp pour extraire les points clés de la caméra également).

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

}

Merci beaucoup.

Ale

12voto

Ale Points 235

Après des heures de recherche et de maux de tête ;-) J'ai trouvé le problème. Les images de la caméra et du fichier peuvent toutes deux être stockées dans des objets bitmap, mais leur configuration (Bitmap.Config) est différente : ARGB_8888 pour les images de la caméra et RGB_565 pour celles du fichier. La solution est de changer la configuration bitmap des images du fichier en ARGB_8888 avec la méthode Bitmap.copy.

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

J'espère que cela pourra aider toute personne rencontrant le même problème :-)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X