Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/opencv/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
试图让OpenCV在Java中工作,将两张照片缝合在一起的示例代码_Java_Opencv_Opencv Stitching - Fatal编程技术网

试图让OpenCV在Java中工作,将两张照片缝合在一起的示例代码

试图让OpenCV在Java中工作,将两张照片缝合在一起的示例代码,java,opencv,opencv-stitching,Java,Opencv,Opencv Stitching,我正在尝试在Java中使用OpenCV。我想把两张照片缝在一起。OpenCV是一个C++库,它有一个java包装器。 我从官方网站下载了带有预构建Windows.dll的OpenCV Java: 我正在使用IntelliJ 2016.1.4 我设置了我的项目并将其指向相关的.jar 我在网上找到了如下代码 它无法开箱即用,因此我修复了一些问题,例如: 专用静态最终积分CV_RANSAC=8;//这只是猜测 我跑了。它失败,在以下行出现错误:“错误:(-5)指定的描述符提取器类型不受支持”:fe=

我正在尝试在Java中使用OpenCV。我想把两张照片缝在一起。OpenCV是一个C++库,它有一个java包装器。
  • 我从官方网站下载了带有预构建Windows.dll的OpenCV Java:

  • 我正在使用IntelliJ 2016.1.4

  • 我设置了我的项目并将其指向相关的.jar

  • 我在网上找到了如下代码

  • 它无法开箱即用,因此我修复了一些问题,例如: 专用静态最终积分CV_RANSAC=8;//这只是猜测

  • 我跑了。它失败,在以下行出现错误:“错误:(-5)指定的描述符提取器类型不受支持”:fe=DescriptorExtractor.create(DescriptorExtractor.SURF);我

  • 我尝试了一系列替代算法(ORB、SIFT、BRIENT),但得到了相同的错误

  • 我想让这个代码正常工作。理想情况下,我会得到不使用一堆弃用函数的工作代码…这些函数已经弃用了,但没有注释说明我应该使用什么…这总是让我很恼火

    (更一般地说,我想要任何可以将照片拼接在一起形成全景的Java示例代码。)

    有人能帮忙吗

    import org.opencv.calib3d.Calib3d;
    import org.opencv.core.*;
    import org.opencv.features2d.DescriptorExtractor;
    import org.opencv.features2d.DescriptorMatcher;
    import org.opencv.features2d.FeatureDetector;
    import org.opencv.features2d.Features2d;
    import org.opencv.imgproc.Imgproc;
    
    import java.util.LinkedList;
    import java.util.List;
    
    import static org.opencv.imgcodecs.Imgcodecs.imread;
    import static org.opencv.imgcodecs.Imgcodecs.imwrite;
    
    
    public class ImageStitching {
    
        static Mat image1;
        static Mat image2;
    
        static FeatureDetector fd;
        static DescriptorExtractor fe;
        static DescriptorMatcher fm;
    
    
        // Compulsory
        static{
            try {
                System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
            }
            catch (UnsatisfiedLinkError e) {
                throw new RuntimeException("Couldn't find \"" + Core.NATIVE_LIBRARY_NAME + ".dll .\n"
                        +"You need to add something like this to the run configuration \"VM options\":\n"
                        +"-Djava.library.path=C:\\OpenCvPreBuilt\\opencv\\build\\java\\x64");
            }
        }
    
    
        public static void go()
        {
            //new CvException("hello");
            fd = FeatureDetector.create(FeatureDetector.BRISK);
            fe = DescriptorExtractor.create(DescriptorExtractor.SURF);
            fm = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE);
    
            //images
            image1 = imread("A.jpg");
            image2 = imread("B.jpg");
    
            //structures for the keypoints from the 2 images
            MatOfKeyPoint keypoints1 = new MatOfKeyPoint();
            MatOfKeyPoint keypoints2 = new MatOfKeyPoint();
    
            //structures for the computed descriptors
            Mat descriptors1 = new Mat();
            Mat descriptors2 = new Mat();
    
            //structure for the matches
            MatOfDMatch matches = new MatOfDMatch();
    
            //getting the keypoints
            fd.detect(image1, keypoints1);
            fd.detect(image1, keypoints2);
    
            //getting the descriptors from the keypoints
            fe.compute(image1, keypoints1, descriptors1);
            fe.compute(image2,keypoints2,descriptors2);
    
            //getting the matches the 2 sets of descriptors
            fm.match(descriptors2,descriptors1, matches);
    
            //turn the matches to a list
            List<DMatch> matchesList = matches.toList();
    
            Double maxDist = 0.0; //keep track of max distance from the matches
            Double minDist = 100.0; //keep track of min distance from the matches
    
            //calculate max & min distances between keypoints
            for(int i=0; i<keypoints1.rows();i++){
                Double dist = (double) matchesList.get(i).distance;
                if (dist<minDist) minDist = dist;
                if(dist>maxDist) maxDist=dist;
            }
    
            System.out.println("max dist: " + maxDist );
            System.out.println("min dist: " + minDist);
    
            //structure for the good matches
            LinkedList<DMatch> goodMatches = new LinkedList<DMatch>();
    
            //use only the good matches (i.e. whose distance is less than 3*min_dist)
            for(int i=0;i<descriptors1.rows();i++){
                if(matchesList.get(i).distance<3*minDist){
                    goodMatches.addLast(matchesList.get(i));
                }
            }
    
            //structures to hold points of the good matches (coordinates)
            LinkedList<Point> objList = new LinkedList<Point>(); // image1
            LinkedList<Point> sceneList = new LinkedList<Point>(); //image 2
    
            List<KeyPoint> keypoints_objectList = keypoints1.toList();
            List<KeyPoint> keypoints_sceneList = keypoints2.toList();
    
            //putting the points of the good matches into above structures
            for(int i = 0; i<goodMatches.size(); i++){
                objList.addLast(keypoints_objectList.get(goodMatches.get(i).queryIdx).pt);
                sceneList.addLast(keypoints_sceneList.get(goodMatches.get(i).trainIdx).pt);
            }
    
            System.out.println("\nNum. of good matches" +goodMatches.size());
    
            MatOfDMatch gm = new MatOfDMatch();
            gm.fromList(goodMatches);
    
            //converting the points into the appropriate data structure
            MatOfPoint2f obj = new MatOfPoint2f();
            obj.fromList(objList);
    
            MatOfPoint2f scene = new MatOfPoint2f();
            scene.fromList(sceneList);
    
            //finding the homography matrix
            Mat H = Calib3d.findHomography(obj, scene, CV_RANSAC, 3);
    
            //LinkedList<Point> cornerList = new LinkedList<Point>();
            Mat obj_corners = new Mat(4,1,CvType.CV_32FC2);
            Mat scene_corners = new Mat(4,1,CvType.CV_32FC2);
    
            obj_corners.put(0,0, new double[]{0,0});
            obj_corners.put(0,0, new double[]{image1.cols(),0});
            obj_corners.put(0,0,new double[]{image1.cols(),image1.rows()});
            obj_corners.put(0,0,new double[]{0,image1.rows()});
    
            Core.perspectiveTransform(obj_corners, scene_corners, H);
    
            //structure to hold the result of the homography matrix
            Mat result = new Mat();
    
            //size of the new image - i.e. image 1 + image 2
            Size s = new Size(image1.cols()+image2.cols(),image1.rows());
    
            //using the homography matrix to warp the two images
            Imgproc.warpPerspective(image1, result, H, s);
            int i = image1.cols();
            Mat m = new Mat(result,new Rect(i,0,image2.cols(), image2.rows()));
    
            image2.copyTo(m);
    
            Mat img_mat = new Mat();
    
            Features2d.drawMatches(image1, keypoints1, image2, keypoints2, gm, img_mat, new Scalar(254,0,0),new Scalar(254,0,0) , new MatOfByte(), 2);
    
            //creating the output file
            boolean imageStitched = imwrite("imageStitched.jpg",result);
            boolean imageMatched = imwrite("imageMatched.jpg",img_mat);
        }
    
    
        public static void main(String args[])
        {
            go();
        }
    }
    
    import org.opencv.calib3d.calib3d;
    导入org.opencv.core.*;
    导入org.opencv.features2d.descriptor;
    导入org.opencv.features2d.DescriptorMatcher;
    导入org.opencv.features2d.FeatureDetector;
    导入org.opencv.features2d.features2d;
    导入org.opencv.imgproc.imgproc;
    导入java.util.LinkedList;
    导入java.util.List;
    导入静态org.opencv.imgcodecs.imgcodecs.imread;
    导入静态org.opencv.imgcodecs.imgcodecs.imwrite;
    公共类图像拼接{
    静态Mat图像1;
    静态Mat图像2;
    静态特性检测器;
    静态描述符;
    静态描述符;
    //强制的
    静止的{
    试一试{
    System.loadLibrary(Core.NATIVE\u LIBRARY\u NAME);
    }
    捕获(未满足链接错误e){
    抛出新的运行时异常(“找不到\”“+Core.NATIVE\u LIBRARY\u NAME+”.dll。\n
    +“您需要在运行配置\“VM选项\”中添加类似的内容:\n”
    +“-Djava.library.path=C:\\opencvprebuild\\opencv\\build\\java\\x64”);
    }
    }
    公共静态void go()
    {
    //新的例外(“你好”);
    fd=FeatureDetector.create(FeatureDetector.BRISK);
    fe=描述符RExtractor.create(描述符RExtractor.SURF);
    fm=DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE);
    //图像
    image1=imread(“A.jpg”);
    image2=imread(“B.jpg”);
    //两幅图像中关键点的结构
    MatOfKeyPoint keypoints1=新的MatOfKeyPoint();
    MatOfKeyPoint keypoints2=新的MatOfKeyPoint();
    //计算描述符的结构
    材料描述符1=新材料();
    材料描述符2=新材料();
    //比赛的结构
    MatOfDMatch matches=新的MatOfDMatch();
    //获取关键点
    fd.检测(图像1,关键点1);
    fd.检测(图像1,关键点2);
    //从关键点获取描述符
    fe.计算(图像1,关键点1,描述符1);
    fe.计算(图像2,关键点2,描述符2);
    //获取与2组描述符匹配的
    匹配(描述符2,描述符1,匹配);
    //将匹配项转到列表
    List matchesList=matches.toList();
    Double maxDist=0.0;//跟踪与匹配项的最大距离
    Double Minist=100.0;//记录与比赛的最小距离
    //计算关键点之间的最大和最小距离
    对于(inti=0;iSo),让我们再试一次。
    我将跳过所有初始化的内容,因为您似乎已经成功加载了库

    对于我的环境:

    • 我在android上使用OpenCV和您自己链接的下载提供的股票Java包装器
    • OpenCV在版本3.4.1中使用
    • 我在Android Studio 3.1.3中开发
    我尽可能在代码中添加注释,并添加源代码(stackoverflow或其他),以显示我在哪里找到代码

    在这一点上,非常感谢这些人帮助我拼凑出一些真正有效的东西

    以下方法是将两个图像缝合在一起的方法 (从AsyncTask中提取,因为它需要很多时间):

    受保护位图背景(位图…arg0){
    //基本代码提取自:http://privateblog.info/sozdanie-panoramy-s-pomoshhyu-opencv-i-java/
    // https://stackoverflow.com/questions/36691050/opencv-3-list-of-available-featuredetectorcreate-and-descriptorextractorc
    // https://stackoverflow.com/questions/27681389/how-to-multiply-2-matrices-in-java-and-then-use-the-result-as-transformation-mat
    //测量持续时间
    long startTime=System.nanoTime();
    //如果获取的图像数量不正确,请中止。。。
    //不支持缝合两个以上的图像。
    如果(arg0.length!=2){
    返回null;
    }
    //从给定的参数中获取两个图像
    位图bitmap1=arg0[0];
    位图bitmap2=arg0[1];
    //如果出现问题,请中止。。。
    如果(位图1==null | |位图2==null){
    返回null;
    }
    //将两个位图转换为OpenCV mats。。。
    Mat img1=新Mat();
    Mat img2=新Mat();
    bitmapToMat(bitmap1,img1);
    Utils.bitmapToMat(bitmap2,img2);
    //…然后创建灰度版本
    Mat gray_image1=新Mat();
    Mat gray_image2=新Mat();
    Imgproc.cvt颜色(img1,灰色\u图像1,Imgproc.COLOR\u rgb2灰色);
    Imgproc.CVT颜色(img2,灰色图像2,Imgproc.COLOR\U RGB2GRAY);
    //在这一点上,大海
    
            protected Bitmap doInBackground(Bitmap...arg0) {
    
            // Base code extracted from: http://privateblog.info/sozdanie-panoramy-s-pomoshhyu-opencv-i-java/
            // https://stackoverflow.com/questions/36691050/opencv-3-list-of-available-featuredetectorcreate-and-descriptorextractorc
            // https://stackoverflow.com/questions/27681389/how-to-multiply-2-matrices-in-java-and-then-use-the-result-as-transformation-mat
            // Measuring the duration
            long startTime = System.nanoTime();
    
            // Abort if we got not the right amount of images...
            // Stitching more than two images is not supported.
            if (arg0.length != 2) {
                return null;
            }
    
            // Get the two images from the given arguments
            Bitmap bitmap1 = arg0[0];
            Bitmap bitmap2 = arg0[1];
    
            // If something is wrong, abort...
            if (bitmap1 == null || bitmap2 == null) {
                return null;
            }
    
            // Convert the two bitmaps to OpenCV mats...
            Mat img1 = new Mat();
            Mat img2 = new Mat();
    
            Utils.bitmapToMat(bitmap1, img1);
            Utils.bitmapToMat(bitmap2, img2);
    
            // ...then create greyscale versions
            Mat gray_image1 = new Mat();
            Mat gray_image2 = new Mat();
    
            Imgproc.cvtColor(img1, gray_image1, Imgproc.COLOR_RGB2GRAY);
            Imgproc.cvtColor(img2, gray_image2, Imgproc.COLOR_RGB2GRAY);
    
            // At this point search for keypoints in both images and compute the matches
            MatOfKeyPoint keyPoints1 = new MatOfKeyPoint();
            MatOfKeyPoint keyPoints2 = new MatOfKeyPoint();
    
            Mat descriptors1 = new Mat();
            Mat descriptors2 = new Mat();
    
            // Since FeatureDetector and Descriptor extractor are marked deprecated and
            // crash whatever value they get, use this construct for detecting and computing...
            // Source: https://stackoverflow.com/questions/36691050/opencv-3-list-of-available-featuredetectorcreate-and-descriptorextractorc
            KAZE kaze = KAZE.create();
            kaze.detect(gray_image1, keyPoints1);
            kaze.detect(gray_image2, keyPoints2);
            kaze.compute(gray_image1, keyPoints1, descriptors1);
            kaze.compute(gray_image2, keyPoints2, descriptors2);
    
            MatOfDMatch matches = new MatOfDMatch();
    
            DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.FLANNBASED);
            matcher.match(descriptors1, descriptors2, matches);
    
            // Calculate min and max distance between the keypoints in the two images.
            double max_dist = 0; double min_dist = 100;
            List<DMatch> listMatches = matches.toList();
    
            for( int i = 0; i < listMatches.size(); i++ ) {
                double dist = listMatches.get(i).distance;
                if( dist < min_dist ) min_dist = dist;
                if( dist > max_dist ) max_dist = dist;
            }
    
            Log.i(this.getClass().getSimpleName(), "Min: " + min_dist);
            Log.i(this.getClass().getSimpleName(), "Max: " + max_dist);
    
            // Reduce the list of matching keypoints to a list of good matches...
            LinkedList<DMatch> good_matches = new LinkedList<DMatch>();
            MatOfDMatch goodMatches = new MatOfDMatch();
            for(int i = 0; i < listMatches.size(); i++) {
                if(listMatches.get(i).distance < 2*min_dist) {
                    good_matches.addLast(listMatches.get(i));
                }
            }
    
            goodMatches.fromList(good_matches);
            Log.i(this.getClass().getSimpleName(), "Number of matches: " + listMatches.size());
            Log.i(this.getClass().getSimpleName(), "Number of good matches: " + good_matches.size());
    
            // Calculate the homograohy between the two images...
            LinkedList<Point> imgPoints1List = new LinkedList<Point>();
            LinkedList<Point> imgPoints2List = new LinkedList<Point>();
            List<KeyPoint> keypoints1List = keyPoints1.toList();
            List<KeyPoint> keypoints2List = keyPoints2.toList();
    
            for(int i = 0; i<good_matches.size(); i++) {
                imgPoints1List.addLast(keypoints1List.get(good_matches.get(i).queryIdx).pt);
                imgPoints2List.addLast(keypoints2List.get(good_matches.get(i).trainIdx).pt);
            }
    
            MatOfPoint2f obj = new MatOfPoint2f();
            obj.fromList(imgPoints1List);
            MatOfPoint2f scene = new MatOfPoint2f();
            scene.fromList(imgPoints2List);
    
            Mat H = Calib3d.findHomography(obj, scene, Calib3d.RANSAC,3);
    
            int imageWidth = img2.cols();
            int imageHeight = img2.rows();
    
            // To avoid missing some of the possible stitching scenarios, we offset the homography to the middle of a mat which has three time the size of one of the pictures.
            // Extracted from this: https://stackoverflow.com/questions/21618044/stitching-2-images-opencv
            Mat Offset = new Mat(3, 3, H.type());
            Offset.put(0,0, new double[]{1});
            Offset.put(0,1, new double[]{0});
            Offset.put(0,2, new double[]{imageWidth});
            Offset.put(1,0, new double[]{0});
            Offset.put(1,1, new double[]{1});
            Offset.put(1,2, new double[]{imageHeight});
            Offset.put(2,0, new double[]{0});
            Offset.put(2,1, new double[]{0});
            Offset.put(2,2, new double[]{1});
    
            // Multiply the homography mat with the offset.
            Core.gemm(Offset, H, 1, new Mat(), 0, H);
    
            Mat obj_corners = new Mat(4,1,CvType.CV_32FC2);
            Mat scene_corners = new Mat(4,1,CvType.CV_32FC2);
    
            obj_corners.put(0,0, new double[]{0,0});
            obj_corners.put(0,0, new double[]{imageWidth,0});
            obj_corners.put(0,0,new double[]{imageWidth,imageHeight});
            obj_corners.put(0,0,new double[]{0,imageHeight});
    
            Core.perspectiveTransform(obj_corners, scene_corners, H);
    
            // The resulting mat will be three times the size (width and height) of one of the source images. (We assume, that both images have the same size.
            Size s = new Size(imageWidth *3,imageHeight*3);
            Mat img_matches = new Mat(new Size(img1.cols()+img2.cols(),img1.rows()), CvType.CV_32FC2);
    
            // Perform the perspective warp of img1 with the given homography and place it on the large result mat.
            Imgproc.warpPerspective(img1, img_matches, H, s);
    
            // Create another mat which is used to hold the second image and place it in the middle of the large sized result mat.
            int m_xPos = (int)(img_matches.size().width/2 - img2.size().width/2);
            int m_yPos = (int)(img_matches.size().height/2 - img2.size().height/2);
            Mat m = new Mat(img_matches,new Rect(m_xPos, m_yPos, img2.cols(), img2.rows()));
    
            // Copy img2 to the mat in the middle of the large result mat
            img2.copyTo(m);
    
            // Some debug logging... and some duration logging following...
            Log.i(this.getClass().getSimpleName(), "Size of img2: width=" + img2.size().width + "height=" + img2.size().height);
            Log.i(this.getClass().getSimpleName(), "Size of m: width=" + m.size().width + "height=" + m.size().height);
            Log.i(this.getClass().getSimpleName(), "Size of img_matches: width=" + img_matches.size().width + "height=" + img_matches.size().height);
    
            long elapsedTime = System.nanoTime() - startTime;
            elapsedTime = elapsedTime / 1000000; // Milliseconds (1:1000000)
            Log.i(this.getClass().getSimpleName(), "Stitching 2 images took " + elapsedTime + "ms");
            //loadedImagesText.append("Stitching 2 images took " + elapsedTime + "ms\n");
    
            // The resulting mat is way to big. It holds a lot of empty "transparent" space.
            // We will not crop the image, so that only the "region of interest" remains.
            startTime = System.nanoTime();
            int stepping = 6;
    
            Rect imageBoundingBox3 = findImageBoundingBox2(img_matches, stepping, true);
    
            elapsedTime = System.nanoTime() - startTime;
            elapsedTime = elapsedTime / 1000000; // Milliseconds (1:1000000)
            Log.i(this.getClass().getSimpleName(), "Resulting rect has tl(x=" + imageBoundingBox3.tl().x + ", y=" + imageBoundingBox3.tl().y +") and br(x=" + imageBoundingBox3.br().x + ", y=" + imageBoundingBox3.br().y +") with stepping="+stepping+" and auto-correct=true\n");
            Log.i(this.getClass().getSimpleName(), "Cropping stitched image (v2.1) took " + elapsedTime + "ms");
    
            //loadedImagesText.append("Resulting rect has tl(x=" + imageBoundingBox3.tl().x + ", y=" + imageBoundingBox3.tl().y +") and br(x=" + imageBoundingBox3.br().x + ", y=" + imageBoundingBox3.br().y +") with stepping="+stepping+" and auto-correct=true\n");
            //loadedImagesText.append("Cropping stitched image (v2.1) took " + elapsedTime + "ms\n");
    
            // Extract the calculated region of interest from the result mat.
            Mat regionOfInterest = img_matches.submat(imageBoundingBox3);
    
            // Convert the end result to a bitmap and we are done!
            Bitmap resultBitmap = Bitmap.createBitmap(regionOfInterest.cols(),  regionOfInterest.rows(),Bitmap.Config.ARGB_8888);
            Utils.matToBitmap(regionOfInterest, resultBitmap);
    
            return resultBitmap;
        }