JavaCV透视校正

标签 java c++ opencv javacv perspective

我将使用 OpenCV 和 C++ 实现的透视校正代码转换为: https://opencv-code.com/tutorials/automatic-perspective-correction-for-quadrilateral-objects/

获取以下用Java实现的OpenCV代码:

public class project 
{
static Point2f center;
public static void main(String args[])
{
    System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    center = new Point2f(0,0);
    Mat src = new Mat();
    src = Highgui.imread("image.jpg");
    if(src == null)
    {
        System.out.println("Image not loaded");
        System.exit(1);
    }

    Mat bw = new Mat();

    Imgproc.cvtColor(src, bw, Imgproc.COLOR_BGR2GRAY);
    Imgproc.blur(bw, bw, new Size(3,3));
    Imgproc.Canny(bw, bw, 100, 100, 3,true);

     Mat lines = new Mat();
        int threshold = 70;
        int minLineSize = 30;
        int lineGap = 10;

        Imgproc.HoughLinesP(bw, lines, 1, Math.PI / 180, threshold,
                minLineSize, lineGap);

        for (int x = 0; x < lines.cols(); x++) 
        {

            double[] vec = lines.get(0, x);
            double[] val = new double[4];

            val[0] = 0;
            val[1] = ((float) vec[1] - vec[3]) / (vec[0] - vec[2]) * -vec[0] + vec[1];
            val[2] = src.cols();
            val[3] = ((float) vec[1] - vec[3]) / (vec[0] - vec[2]) * (src.cols() - vec[2]) + vec[3];

            lines.put(0, x, val);

        }

        List<Point2f> corners = new ArrayList<Point2f>();
        for (int i = 0; i < lines.cols(); i++)
        {
            for (int j = i+1; j < lines.cols(); j++)
            {
                Mat m1 = null,m2 = null;
                double[] d1 = lines.get(0,i);
                double[] d2 = lines.get(0, j);
                m1.put(0, i, d1);
                m2.put(0, j, d2);
                Point2f pt = computeIntersect(m1, m2);
                if (pt.x >= 0 && pt.y >= 0)
                    corners.add(pt);
            }
        }

        List<Point2f> approx = new ArrayList<Point2f>();
        List<Point2f> curve;
        MatOfPoint2f mat2f = new MatOfPoint2f();
        for(int k=0;k<corners.size();++k)
        {
            Point2f rec = corners.get(k);
            Point p = new Point(rec.x,rec.y);
            mat2f.fromArray(p);
        }
        MatOfPoint2f mat2frec = new MatOfPoint2f();
        Imgproc.approxPolyDP(mat2f, mat2frec, Imgproc.arcLength(mat2f, true) * 0.02,true);

        if (approx.size() != 4)
        {
            System.out.println("The object is not quadrilateral!");

        }

        // Get mass center
        for (int i = 0; i < corners.size(); i++)
        {
            center.x = center.x + corners.get(i).x;
            center.y = center.y + corners.get(i).y;
        }
        center.x *= (1. / corners.size());
        center.y *= (1. / corners.size());

        sortCorners(corners, center);

        Mat dst = src.clone();

        // Draw lines
        for (int i = 0; i < lines.cols(); i++)
        {
            double[] v = lines.get(0, i);
            Scalar cc = new Scalar(0,255,0,0);
            Core.line(dst, new Point(v[0], v[1]), new Point(v[2], v[3]), cc);

        }

        Scalar c1 = new Scalar(0,0,255,0);
        Scalar c2 = new Scalar(0,255,0,0);
        Scalar c3 = new Scalar(255,0,0,0);
        Scalar c4 = new Scalar(255,255,255,0);

        // Draw corner points

        Core.circle(dst, new Point(corners.get(0).x,corners.get(0).y), 3, c1, 2);
        Core.circle(dst, new Point(corners.get(1).x,corners.get(1).y), 3, c2, 2);
        Core.circle(dst, new Point(corners.get(2).x,corners.get(2).y), 3, c3, 2);
        Core.circle(dst, new Point(corners.get(3).x,corners.get(3).y), 3, c4, 2);

        Scalar c5 = new Scalar(0,255,255,0);
        // Draw mass center
        Core.circle(dst, new Point(center.x,center.y), 3, c5, 2);

        Mat quad = Mat.zeros(300, 220, CvType.CV_8UC3);

        List<Point2f> quad_pts = new ArrayList<Point2f>();
        quad_pts.add(new Point2f(0, 0));
        quad_pts.add(new Point2f(quad.cols(), 0));
        quad_pts.add(new Point2f(quad.cols(), quad.rows()));
        quad_pts.add(new Point2f(0, quad.rows()));


        Mat transmtx = Imgproc.getPerspectiveTransform((Mat) corners, (Mat) quad_pts);
        Imgproc.warpPerspective(src, quad, transmtx, quad.size());

        MatOfByte matOfByte = new MatOfByte();

        Highgui.imencode(".jpg", dst, matOfByte); 
        byte[] byteArray = matOfByte.toArray();
        BufferedImage bufImage = null;
        try 
        {
            InputStream in = new ByteArrayInputStream(byteArray);
            bufImage = ImageIO.read(in);
            File outputfile = new File("Image.jpg");
            ImageIO.write(bufImage, "jpg", outputfile);
        } 
        catch (Exception e) {
            e.printStackTrace();
        }

        MatOfByte matOfByte2 = new MatOfByte();

        Highgui.imencode(".jpg", dst, matOfByte2); 
        byte[] byteArray2 = matOfByte2.toArray();
        BufferedImage bufImage2 = null;
        try 
        {
            InputStream in = new ByteArrayInputStream(byteArray2);
            bufImage2 = ImageIO.read(in);
            File outputfile2 = new File("Quadrilateral.jpg");
            ImageIO.write(bufImage, "jpg", outputfile2);
        } 
        catch (Exception e) {
            e.printStackTrace();
        }


}
static Point2f computeIntersect(Mat es, Mat es2)
{
    int size = (int) es.total() * es.channels();
    float[] buff = new float[size];
    es.get(0, 0, buff);

    int size1 = (int) es.total() * es.channels();
    float[] buff1 = new float[size1];
    es.get(0, 0, buff1);

    float x1=buff[0], y1 = buff[1], x2 = buff[2], y2 = buff[3];
    float x3 = buff1[0], y3 = buff1[1], x4 = buff1[2], y4 = buff1[3];
    float denom;
    float d;
    d = (Float) null;
    d = (float)((x1 - x2) * (y3 - y4)) - ((y1 - y2) * (x3 - x4));
    if (d != (Float) null)
    {
        Point2f pt = new Point2f();
        pt.x = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / d;
        pt.y = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / d;
        return pt;
    }
    else
        return new Point2f(-1, -1);
}

static void sortCorners(List<Point2f> corners,Point2f center)
{
    List<Point2f> top = null, bot = null;

    for (int i = 0; i < corners.size(); i++)
    {
        if (corners.get(i).y < center.y)
            top.add(corners.get(i));
        else
            bot.add(corners.get(i));
    }

    Point2f tl = top.get(0).x > top.get(1).x ? top.get(1) : top.get(0);
    Point2f tr = top.get(0).x > top.get(1).x ? top.get(0) : top.get(1);
    Point2f bl = bot.get(0).x > bot.get(1).x ? bot.get(1) : bot.get(0);
    Point2f br = bot.get(0).x > bot.get(1).x ? bot.get(0) : bot.get(1);

    corners.clear();
    corners.add(tl);
    corners.add(tr);
    corners.add(br);
    corners.add(bl);
}



}

我在将 List 转换为 MatOfPoint2f 时遇到问题。因此 arcLength(..) 函数不起作用,代码似乎不起作用。我希望有人能提供帮助。

最佳答案

这是我在我的项目中使用的实现的一部分。我已经使用我开发的算法获得了确切的角点,但其余部分在此代码中给出。不要使用 point2fs。使用点数组并将它们转换为 matofpoint2fs。

可以从这里下载包含 Imshow 的 jarfile。它在任何时间点测试您的 o/p 都非常有效。将此包添加到您的程序中:https://github.com/master-atul/ImShow-Java-OpenCV

关于 approxpolydp 的详细信息: http://docs.opencv.org/java/org/opencv/imgproc/Imgproc.html#approxPolyDP%28org.opencv.core.MatOfPoint2f,org.opencv.core.MatOfPoint2f,double,boolean%29

而且您不必使用弧长。只需根据输入的清晰度给出 epsilon 的近似值即可。(例如 2.0 或 3.0..)

(sort是用来对角进行排序的函数)

int a[][],imgarr[][];

Point p[];

BufferedImage img;

int w,h;
void sort()
{
int x = (a[0][0] + a[1][0] + a[2][0] + a[3][0])/4;
int y = (a[0][1] + a[1][1] + a[2][1] + a[3][1])/4;
int j = 0;
int order[] = new int[4];
double tans[] = new double[4];
double tans1[] = new double[4];
int tmpar[][] = new int[4][2];
p = new Point[4];       
for(int i = 0;i<4;i++)
{
tans1[i] = tans[i] = Math.atan2(a[i][1] - y , a[i][0] - x);//finding angles for sorting corners 
}
Arrays.sort(tans1);
for(int i = 0;i<2;i++)
{
double temp = tans1[i];
tans1[i]= tans1[3-i];
tans1[3-i] = temp;
}
for(int i=0;i<4;i++)
{
for(j = 0;j<4;j++)
{
    if(tans1[i]==tans[j])
        break;
}
order[i] = j;
}
for(int i = 0;i<4;i++)
{
for(j=0;j<2;j++)
{
    tmpar[i][j] = a[i][j];
}
}
for(int i = 0;i<4;i++)
{
for(j = 0;j<2;j++)
{
        a[i][j] = tmpar[order[i]][j];
        }
    }
    p[0] = new Point(a[0][1],a[0][0]);
    p[1] = new Point(a[1][1],a[1][0]);
    p[2] = new Point(a[2][1],a[2][0]);
    p[3] = new Point(a[3][1],a[3][0]);
}
void transform() throws Exception
{
    Point farray[] = new Point[4];      
    try
    {
        img = ImageIO.read(new File("C:/Users/Documents/a.jpg"));
    }
    catch(Exception r)
    {
        System.out.println("no file");
    }
    PixelGrabber pg;
    if(img==null)
    {
        return;
    }
    w = img.getWidth();
    h = img.getHeight();
    imgarr = new int[h][w];
    try
    {           
        for(int i = 0; i < h ; i++)
        {
            pg = new PixelGrabber(img,0,i,w,1,imgarr[i],0,w);               
            pg.grabPixels();    
        }
        changeto256();
    }
    catch(Exception e)
    {
        System.out.println("here "+e);
    }
    int m=0;        
    byte array[] = new byte[w*h];
    int iar[] = new int[w*h];
    for(int i = 0 ; i < h ; i++)
    {
        for(int j = 0 ; j < w ; j++)
        {
            array[m++]= (byte)imgarr[i][j];
        }
    }
    farray[3] = new Point(0,0);
    farray[0] = new Point(w,0);
    farray[1] = new Point(w,h);
    farray[2] = new Point(0,h);


    Mat mat = new Mat(h,w, CvType.CV_8U);
    mat.put(0, 0, array);
    Imshow is = new Imshow("try");
    MatOfPoint2f quad = new MatOfPoint2f(p);
    MatOfPoint2f rect = new MatOfPoint2f(farray);
    Mat transmtx = Imgproc.getPerspectiveTransform(quad,rect);
    Mat output = new Mat(w,h,CvType.CV_8U); 
    Imgproc.warpPerspective(mat, output, transmtx, new size(w,h),Imgproc.INTER_CUBIC);
    is.showImage(output);       
    MatOfByte matOfByte = new MatOfByte();
    Highgui.imencode(".jpg", output, matOfByte); 
    byte[] byteArray = matOfByte.toArray();
    File f = new File("retrieve1.jpg");
    BufferedImage img1 =null;
    InputStream in = new ByteArrayInputStream(byteArray);
    img1  = ImageIO.read(in);
    WritableRaster raster = (WritableRaster)img1.getData();
    raster.setDataElements(0,0,byteArray);
    img1.setData(raster);
    try
    {
        ImageIO.write(img1,"jpg",f);
    }
    catch(Exception e)
    {}
}

关于JavaCV透视校正,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21571761/

相关文章:

java - 复制文件的文件创建日期java nio

opencv - 为什么 “train data must be floating-point matrix”运行时错误?

c++ - 访问 cvCreateMatND 的元素

python - OpenCV安装目录只有一个.so文件?

java - NoSuchMethodError : javassist. CtClass.getDeclaredClasses()

java - OCA Java SE 7 1Z0-803/804 认证的书籍/资源建议

java - 用于远程启动服务的 CMD 命令不在代码中运行,而是在 CMD 上运行

c++ - 将宏定义的函数转换为 C++ 中的模板

c++ - 运行时计时功能和命令行时间之间的区别

c++ - ClangAST Consumer : How to traverse statements, VarDecl,FunctionDecl 中的 BinaryOperator?