实现效果

相机拍照,对图片进行倾斜矫正

安卓opencv 安卓opencv图像教正_特征点

图片矫正实现步骤
  1. 读取图片到内存。
  2. 为两张图检测ORB特征点
  3. 特征匹配:找到两图中匹配的特征点,并按照匹配度排列,保留最匹配的一小部分。然后把匹配的特征点画出来并保存图片。
  4. 计算单应性矩阵:由于上一步产生的匹配的特征点不是100%正确的,需要调用findHomography 函数来计算多个二维点对之间的最优单应性变换矩阵。
  5. 透视变换:有了精确的单应性矩阵,就可以把一张图片的所有像素映射到另一个图片。使用透视变换 来完成图片矫正。
透视变换

透视变换(Perspective Transformation)是指利用透视中心、像点、目标点三点共线的条件,按透视旋转定律使承影面(透视面)绕迹线(透视轴)旋转某一角度,破坏原有的投影光线束,仍能保持承影面上投影几何图形不变的变换。透视变换是按照物体成像投影规律进行变换,即将物体重新投影到新的成像平面。透视变换常用于机器人视觉导航研究中,由于相机视场与地面存在倾斜角使得物体成像产生畸变,通常通过透视变换实现对物体图像的校正。

/**
		src  原图
		dst  透视变换后输出图像,与src数据类型相同,但是尺寸与dsize相同
		M  3*3变换矩阵
		dsize  输出图像的尺寸
		flags  插值方法标志
		borderMode  像素边界外推方法的标志。BORDER_CONSTANT 或者BORDER_REPLICATE
		borderValue  填充边界使用的数值,默认情况下为0
**/
  public static void warpPerspective(Mat src, Mat dst, Mat M, Size dsize, int flags, int borderMode, Scalar borderValue)
实现拍照图片矫正代码带注释
/**
     * 图片纠正
     * @param context
     * @param bitmap
     * @param iv
     * @return
     * @throws IOException
     */
    public static Point alignImages(Context context, Bitmap bitmap, ImageView iv) throws IOException {

        //读取的原图
        Mat real = new Mat();
        Mat grayReal = Utils.loadResource(context, R.drawable.shujiattl1);
        Imgproc.cvtColor(grayReal, real, Imgproc.COLOR_BGR2GRAY);
        //拍照图
        Mat mSource = new Mat();
        Utils.bitmapToMat(bitmap, mSource);
        Mat sourceMat = new Mat();
        Imgproc.cvtColor(mSource,sourceMat,Imgproc.COLOR_BGR2GRAY);
        //原图特征点
        MatOfKeyPoint real_point = new MatOfKeyPoint();
        //拍照图特征点
        MatOfKeyPoint source_point = new MatOfKeyPoint();
        Mat real1 = new Mat();
        Mat source1 = new Mat();
        //为两张图检测ORB特征点
        orbFeatures(sourceMat,source_point,source1);
        orbFeatures(real,real_point,real1);
        //特征点匹配
        MatOfDMatch matches = new MatOfDMatch();
        BFMatcher matcher = BFMatcher.create(Core.NORM_HAMMING);
        matcher.match(source1, real1, matches);

        List<DMatch> list = matches.toList();

        Collections.sort(list,new Comparator<DMatch>() {
            @Override
            public int compare(DMatch o1, DMatch o2) {
                return Double.compare(o1.distance,o2.distance);
            }
        });
//        float min = list.get(0).distance;
        List<DMatch> goodMatchers = new ArrayList<>();
        for (int i = 0; i < list.size()*0.15; i++) {
            goodMatchers.add(list.get(i));
        }

        Log.e("dbj", " goodMatchers size = "+goodMatchers.size());
        Mat result =new Mat();
        MatOfDMatch matOfDMatch = new MatOfDMatch();
        matOfDMatch.fromList(goodMatchers);
        //绘制特征点
        drawMatches(sourceMat, source_point, real, real_point, matOfDMatch, result);

        List<Point> matOfPoint2fList_source = new ArrayList<>();
        List<Point> matOfPoint2fList_real = new ArrayList<>();
        MatOfPoint2f sourcePoints = new MatOfPoint2f();
        MatOfPoint2f realPoints = new MatOfPoint2f();
        for (int i = 0; i < goodMatchers.size(); i++) {
            matOfPoint2fList_source.add(source_point.toArray()[goodMatchers.get(i).queryIdx].pt);
            matOfPoint2fList_real.add(real_point.toArray()[goodMatchers.get(i).trainIdx].pt);
        }
        sourcePoints.fromList(matOfPoint2fList_source);
        realPoints.fromList(matOfPoint2fList_real);
        //计算单应性矩阵
        Mat homography = findHomography(sourcePoints, realPoints, RANSAC);
        //图片矫正
        Mat img = new Mat();
        Imgproc.warpPerspective(
                mSource,
                img,
                homography,
                new Size(real.width(), real.height())
        );
        //以下是求点操作,可以不用管
        List<Point> points = getPoint(context,img,iv);
        if (points==null){
            return null;
        }
        //这是我求的左上角的点
        return points.get(0);

    }



    private static void orbFeatures(Mat source, MatOfKeyPoint keyPoints,Mat descriptor) {
        ORB orbDetector = ORB.create(
                1000,
                1.2f
        );
        orbDetector.detect(source, keyPoints);
        orbDetector.compute(source, keyPoints, descriptor);

    }