我正在尝试学习计算机视觉,特别是在物体识别和图像匹配方面。我遇到过各种方法,如SIFT,SURF和ORB。到目前为止,我尝试在Android中使用开放式CV并找到此tutorial
这是代码初始化openCV:
private void initializeOpenCVDependencies() throws IOException {
mOpenCvCameraView.enableView();
detector = FeatureDetector.create(FeatureDetector.ORB);
descriptor = DescriptorExtractor.create(DescriptorExtractor.ORB);
matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING);
img1 = new Mat();
AssetManager assetManager = getAssets();
InputStream istr = assetManager.open("a.jpeg");
Bitmap bitmap = BitmapFactory.decodeStream(istr);
Utils.bitmapToMat(bitmap, img1);
Imgproc.cvtColor(img1, img1, Imgproc.COLOR_RGB2GRAY);
img1.convertTo(img1, 0); //converting the image to match with the type of the cameras image
descriptors1 = new Mat();
keypoints1 = new MatOfKeyPoint();
detector.detect(img1, keypoints1);
descriptor.compute(img1, keypoints1, descriptors1);
}
以及我用来识别对象的代码:
public Mat recognize(Mat aInputFrame) {
Imgproc.cvtColor(aInputFrame, aInputFrame, Imgproc.COLOR_RGB2GRAY);
descriptors2 = new Mat();
keypoints2 = new MatOfKeyPoint();
detector.detect(aInputFrame, keypoints2);
descriptor.compute(aInputFrame, keypoints2, descriptors2);
// Matching
MatOfDMatch matches = new MatOfDMatch();
if (img1.type() == aInputFrame.type()) {
matcher.match(descriptors1, descriptors2, matches);
} else {
return aInputFrame;
}
List<DMatch> matchesList = matches.toList();
Double max_dist = 0.0;
Double min_dist = 100.0;
for (int i = 0; i < matchesList.size(); i++) {
Double dist = (double) matchesList.get(i).distance;
if (dist < min_dist)
min_dist = dist;
if (dist > max_dist)
max_dist = dist;
}
LinkedList<DMatch> good_matches = new LinkedList<DMatch>();
for (int i = 0; i < matchesList.size(); i++) {
if (matchesList.get(i).distance <= (1.5 * min_dist))
good_matches.addLast(matchesList.get(i));
}
MatOfDMatch goodMatches = new MatOfDMatch();
goodMatches.fromList(good_matches);
Mat outputImg = new Mat();
MatOfByte drawnMatches = new MatOfByte();
if (aInputFrame.empty() || aInputFrame.cols() < 1 || aInputFrame.rows() < 1) {
return aInputFrame;
}
Features2d.drawMatches(img1, keypoints1, aInputFrame, keypoints2, goodMatches, outputImg, GREEN, RED, drawnMatches, Features2d.NOT_DRAW_SINGLE_POINTS);
Imgproc.resize(outputImg, outputImg, aInputFrame.size());
return outputImg;
}
这是完整的代码:
public class MainActivity extends AppCompatActivity implements CameraBridgeViewBase.CvCameraViewListener2 {
/*ImageView imageView1;
Context context;
Bitmap img;*/
private static final String TAG = "OCVSample::Activity";
private int w, h;
private CameraBridgeViewBase mOpenCvCameraView;
TextView tvName;
Scalar RED = new Scalar(255, 0, 0);
Scalar GREEN = new Scalar(0, 255, 0);
FeatureDetector detector;
DescriptorExtractor descriptor;
DescriptorMatcher matcher;
Mat descriptors2,descriptors1;
Mat img1;
MatOfKeyPoint keypoints1,keypoints2;
static {
if (!OpenCVLoader.initDebug())
Log.d("ERROR", "Unable to load OpenCV");
else
Log.d("SUCCESS", "OpenCV loaded");
}
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
@Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS: {
Log.i(TAG, "OpenCV loaded successfully");
mOpenCvCameraView.enableView();
try {
initializeOpenCVDependencies();
} catch (IOException e) {
e.printStackTrace();
}
}
break;
default: {
super.onManagerConnected(status);
}
break;
}
}
};
private void initializeOpenCVDependencies() throws IOException {
mOpenCvCameraView.enableView();
detector = FeatureDetector.create(FeatureDetector.ORB);
descriptor = DescriptorExtractor.create(DescriptorExtractor.ORB);
matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING);
img1 = new Mat();
AssetManager assetManager = getAssets();
InputStream istr = assetManager.open("a.jpeg");
Bitmap bitmap = BitmapFactory.decodeStream(istr);
Utils.bitmapToMat(bitmap, img1);
Imgproc.cvtColor(img1, img1, Imgproc.COLOR_RGB2GRAY);
img1.convertTo(img1, 0); //converting the image to match with the type of the cameras image
descriptors1 = new Mat();
keypoints1 = new MatOfKeyPoint();
detector.detect(img1, keypoints1);
descriptor.compute(img1, keypoints1, descriptors1);
}
public MainActivity() {
Log.i(TAG, "Instantiated new " + this.getClass());
}
private static final int CAMERA_PERMISSION_CONSTANT = 100;
private static final int REQUEST_PERMISSION_SETTING = 101;
private boolean sentToSettings = false;
private SharedPreferences permissionStatus;
@Override
protected void onCreate(Bundle savedInstanceState) {
//System.loadLibrary("opencv_java3");
/*imageView1 = findViewById(R.id.imageView1);
img = BitmapFactory.decodeResource(this.getResources(),R.drawable.bg_image);
imageView1.setImageBitmap(img);*/
Log.i(TAG, "called onCreate");
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.activity_main);
permissionStatus = getSharedPreferences("permissionStatus",MODE_PRIVATE);
mOpenCvCameraView = findViewById(R.id.tutorial1_activity_java_surface_view);
startCamera();
mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);
mOpenCvCameraView.setCvCameraViewListener(MainActivity.this);
tvName = findViewById(R.id.text1);
}
public void startCamera(){
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, Manifest.permission.CAMERA)) {
//Show Information about why you need the permission
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle("Need Storage Permission");
builder.setMessage("This app needs storage permission.");
builder.setPositiveButton("Grant", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CAMERA}, CAMERA_PERMISSION_CONSTANT);
}
});
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
builder.show();
} else if (permissionStatus.getBoolean(Manifest.permission.CAMERA,false)) {
//Previously Permission Request was cancelled with 'Dont Ask Again',
// Redirect to Settings after showing Information about why you need the permission
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle("Need Storage Permission");
builder.setMessage("This app needs storage permission.");
builder.setPositiveButton("Grant", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
sentToSettings = true;
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent.setData(uri);
startActivityForResult(intent, REQUEST_PERMISSION_SETTING);
Toast.makeText(getBaseContext(), "Go to Permissions to Grant Storage", Toast.LENGTH_LONG).show();
}
});
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
builder.show();
} else {
//just request the permission
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CAMERA}, CAMERA_PERMISSION_CONSTANT);
}
SharedPreferences.Editor editor = permissionStatus.edit();
editor.putBoolean(Manifest.permission.CAMERA,true);
editor.commit();
} else {
//You already have the permission, just go ahead.
proceedAfterPermission();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == CAMERA_PERMISSION_CONSTANT) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//The External Storage Write Permission is granted to you... Continue your left job...
proceedAfterPermission();
} else {
if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, Manifest.permission.CAMERA)) {
//Show Information about why you need the permission
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle("Need Storage Permission");
builder.setMessage("This app needs storage permission");
builder.setPositiveButton("Grant", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CAMERA}, CAMERA_PERMISSION_CONSTANT);
}
});
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
builder.show();
} else {
Toast.makeText(getBaseContext(),"Unable to get Permission",Toast.LENGTH_LONG).show();
}
}
}
}
private void proceedAfterPermission() {
//We've got the permission, now we can proceed further
Toast.makeText(getBaseContext(), "We got the Storage Permission", Toast.LENGTH_LONG).show();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_PERMISSION_SETTING) {
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
//Got Permission
proceedAfterPermission();
}
}
}
@Override
protected void onPostResume() {
super.onPostResume();
if (sentToSettings) {
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
//Got Permission
proceedAfterPermission();
}
}
}
@Override
public void onPause() {
super.onPause();
if (mOpenCvCameraView != null)
mOpenCvCameraView.disableView();
}
@Override
public void onResume() {
super.onResume();
if (!OpenCVLoader.initDebug()) {
Log.d(TAG, "Internal OpenCV library not found. Using OpenCV Manager for initialization");
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_0_0, this, mLoaderCallback);
} else {
Log.d(TAG, "OpenCV library found inside package. Using it!");
mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
}
}
public void onDestroy() {
super.onDestroy();
if (mOpenCvCameraView != null)
mOpenCvCameraView.disableView();
}
/*public void toGray(View view) {
Mat source = new Mat();
Utils. bitmapToMat( img, source);
Mat dest = new Mat(source.size(), CvType.CV_8UC1);
Imgproc. cvtColor(source, dest, Imgproc.COLOR_RGB2GRAY, 4);
Bitmap btmp = Bitmap.createBitmap(dest.width(),dest.height(),Bitmap.Config.ARGB_8888);
Utils. matToBitmap(dest,btmp);
imageView1.setImageBitmap(btmp);
}*/
@Override
public void onCameraViewStarted(int width, int height) {
w = width;
h = height;
}
public Mat recognize(Mat aInputFrame) {
Imgproc.cvtColor(aInputFrame, aInputFrame, Imgproc.COLOR_RGB2GRAY);
descriptors2 = new Mat();
keypoints2 = new MatOfKeyPoint();
detector.detect(aInputFrame, keypoints2);
descriptor.compute(aInputFrame, keypoints2, descriptors2);
// Matching
MatOfDMatch matches = new MatOfDMatch();
if (img1.type() == aInputFrame.type()) {
matcher.match(descriptors1, descriptors2, matches);
} else {
return aInputFrame;
}
List<DMatch> matchesList = matches.toList();
Double max_dist = 0.0;
Double min_dist = 100.0;
for (int i = 0; i < matchesList.size(); i++) {
Double dist = (double) matchesList.get(i).distance;
if (dist < min_dist)
min_dist = dist;
if (dist > max_dist)
max_dist = dist;
}
LinkedList<DMatch> good_matches = new LinkedList<DMatch>();
for (int i = 0; i < matchesList.size(); i++) {
if (matchesList.get(i).distance <= (1.5 * min_dist))
good_matches.addLast(matchesList.get(i));
}
MatOfDMatch goodMatches = new MatOfDMatch();
goodMatches.fromList(good_matches);
Mat outputImg = new Mat();
MatOfByte drawnMatches = new MatOfByte();
if (aInputFrame.empty() || aInputFrame.cols() < 1 || aInputFrame.rows() < 1) {
return aInputFrame;
}
Features2d.drawMatches(img1, keypoints1, aInputFrame, keypoints2, goodMatches, outputImg, GREEN, RED, drawnMatches, Features2d.NOT_DRAW_SINGLE_POINTS);
Imgproc.resize(outputImg, outputImg, aInputFrame.size());
return outputImg;
}
@Override
public void onCameraViewStopped() {
}
@Override
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
return recognize(inputFrame.rgba());
}
}
我在这一行收到错误,导致应用程序在第一次打开时停止:
matcher.match(descriptors1, descriptors2, matches);
这是stacktrace / logcat:
01-02 15:49:11.496 605-30317/? E/QCamera: <HAL><ERROR> static void*01-02 15:49:11.502 30174-30337/com.rahmat.app.opencvandroid E/AndroidRuntime: FATAL EXCEPTION: Thread-4415
Process: com.rahmat.app.opencvandroid, PID: 30174
CvException [org.opencv.core.CvException: cv::Exception: /build/master_pack-android/opencv/modules/core/src/stat.cpp:4017: error: (-215) type == src2.type() && src1.cols == src2.cols && (type == 5 || type == 0) in function void cv::batchDistance(cv::InputArray, cv::InputArray, cv::OutputArray, int, cv::OutputArray, int, int, cv::InputArray, int, bool)
]
at org.opencv.features2d.DescriptorMatcher.match_1(Native Method)
at org.opencv.features2d.DescriptorMatcher.match(DescriptorMatcher.java:220)
at com.rahmat.app.opencvandroid.MainActivity.recognize(MainActivity.java:328)
at com.rahmat.app.opencvandroid.MainActivity.onCameraFrame(MainActivity.java:374)
at org.opencv.android.CameraBridgeViewBase.deliverAndDrawFrame(CameraBridgeViewBase.java:392)
at org.opencv.android.JavaCameraView$CameraWorker.run(JavaCameraView.java:373)
at java.lang.Thread.run(Thread.java:818)
我认为它与匹配过程有关,任何人都有解决方案吗?或教程/参考/链接将非常感激。