目标

本节内容我们将学习:

  • 通过 line() 方法绘制一条线
  • 通过ellipse() 方法绘制一个椭圆
  • 通过rectangle() 方法绘制一个矩形
  • 通过circle() 方法绘制一个圆形
  • 通过fillPoly() 方法填充一个多边形

OpenCV理论

在本节教程中,我们将着重使用两个类cv::Point 和cv::Scalar 。

用x和y坐标代表二维图像中的一个点,可以用如下代码定义:

Point point = new Point();
        point.x = 10;
        point.y = 8;

或者

Point point1 = new Point(10, 8);
Scalar
  • 代表一个四元素的向量。Scalar类型广泛应用在像素值的传输中。
  • 在本篇教程中我们将会广泛的应用Scalar去表示一个BGR颜色值(3个参数)。我们并不需要去定义最后一个参数值,除非需要的话。
  • 让我们看一下例子:
Scalar scalar = new Scalar(0, 0, 0);

代码

public class Main {
    private static final int W = 400;

    public static void main(String[] args) {
        System.loadLibrary("libs/"+ Core.NATIVE_LIBRARY_NAME);
        String atom_window = "Drawing 1:Atom";
        String rook_window = "Drawing 2:rook";
        Mat atom_image = Mat.zeros(W, W, CvType.CV_8UC3);
        Mat rook_image = Mat.zeros(W, W, CvType.CV_8UC3);
        MyEllipse(atom_image,90.0);
        MyEllipse(atom_image,0.0);
        MyEllipse(atom_image,45.0);
        MyEllipse(atom_image,-45.0);

        MyFilledCircle(atom_image,new Point(W/2,W/2));

        MyPolygon(rook_image);

        rectangle(rook_image,
                new Point(0,7*W/8),
                new Point(W,W),
                new Scalar(0,255,255),
                -1,
                8,
                0);

        MyLine( rook_image, new Point( 0, 15*W/16 ), new Point( W, 15*W/16 ) );
        MyLine( rook_image, new Point( W/4, 7*W/8 ), new Point( W/4, W ) );
        MyLine( rook_image, new Point( W/2, 7*W/8 ), new Point( W/2, W ) );
        MyLine( rook_image, new Point( 3*W/4, 7*W/8 ), new Point( 3*W/4, W ) );

        imshow(atom_window,atom_image);
        moveWindow(atom_window,0,200);
        imshow(rook_window,rook_image);
        moveWindow(rook_window,W,200);
        waitKey();
        System.exit(0);

    }
    private static void MyEllipse(Mat img, double angle){
        int thickness = 2;
        int lineType = 8;
        int shift = 0;
        ellipse(img,
                new Point(W/2,W/2),
                new Size(W/4,W/16),
                angle,
                0.0,
                360.0,
                new Scalar(255,0,0),
                thickness,
                lineType,
                shift);
    }
    public static  void MyFilledCircle(Mat img,Point center){
        int thickness = 2;
        int lineType = 8;
        int shift = 0;
        circle(img,
                center,
                W/32,
                new Scalar(0,0,255),
                thickness,
                lineType,
                shift);
    }
    private static void MyPolygon(Mat img){
        int lineType = 8;
        int shift = 0;
        Point[] rook_points = new Point[20];
        rook_points[0]  = new Point(     W/4, 7*W/8   );
        rook_points[1]  = new Point(   3*W/4, 7*W/8   );
        rook_points[2]  = new Point(   3*W/4, 13*W/16 );
        rook_points[3]  = new Point( 11*W/16, 13*W/16 );
        rook_points[4]  = new Point( 19*W/32, 3*W/8   );
        rook_points[5]  = new Point(   3*W/4, 3*W/8   );
        rook_points[6]  = new Point(   3*W/4, W/8     );
        rook_points[7]  = new Point( 26*W/40, W/8     );
        rook_points[8]  = new Point( 26*W/40, W/4     );
        rook_points[9]  = new Point( 22*W/40, W/4     );
        rook_points[10] = new Point( 22*W/40, W/8     );
        rook_points[11] = new Point( 18*W/40, W/8     );
        rook_points[12] = new Point( 18*W/40, W/4     );
        rook_points[13] = new Point( 14*W/40, W/4     );
        rook_points[14] = new Point( 14*W/40, W/8     );
        rook_points[15] = new Point(     W/4, W/8     );
        rook_points[16] = new Point(     W/4, 3*W/8   );
        rook_points[17] = new Point( 13*W/32, 3*W/8   );
        rook_points[18] = new Point(  5*W/16, 13*W/16 );
        rook_points[19] = new Point(     W/4, 13*W/16 );
        MatOfPoint matPt = new MatOfPoint();
        matPt.fromArray(rook_points);
        ArrayList<MatOfPoint> ppt = new ArrayList<>();
        ppt.add(matPt);
        fillPoly(img,
                ppt,
                new Scalar(255,255,255),
                lineType,
                shift,
                new Point(0,0));
    }
    private static void MyLine(Mat img,Point start, Point end){
        int thickness = 2;
        int lineType = 8;
        int shift = 0;

        line(img,
                start,
                end,
                new Scalar(0,0,0),
                thickness,
                lineType,
                shift);
    }
}

解释

首先我们创建两个窗体和Mat对象用于显示保存我们需要绘制的两个图像:

String atom_window = "Drawing 1:Atom";
        String rook_window = "Drawing 2:rook";
        Mat atom_image = Mat.zeros(W, W, CvType.CV_8UC3);
        Mat rook_image = Mat.zeros(W, W, CvType.CV_8UC3);

我们创建不同的方法去绘制不同的图形。在本例中绘制原子需要用到MyEllipse 和 MyFilledCircle:

MyEllipse(atom_image,90.0);
        MyEllipse(atom_image,0.0);
        MyEllipse(atom_image,45.0);
        MyEllipse(atom_image,-45.0);

        MyFilledCircle(atom_image,new Point(W/2,W/2));

绘制国际象棋需要用到MyLine, rectangle 和a MyPolygon:

MyPolygon(rook_image);

        rectangle(rook_image,
                new Point(0,7*W/8),
                new Point(W,W),
                new Scalar(0,255,255),
                -1,
                8,
                0);

        MyLine( rook_image, new Point( 0, 15*W/16 ), new Point( W, 15*W/16 ) );
        MyLine( rook_image, new Point( W/4, 7*W/8 ), new Point( W/4, W ) );
        MyLine( rook_image, new Point( W/2, 7*W/8 ), new Point( W/2, W ) );
        MyLine( rook_image, new Point( 3*W/4, 7*W/8 ), new Point( 3*W/4, W ) );

接下来让我们看看每个方法内部是怎么实现的:

MyLine
private static void MyLine(Mat img,Point start, Point end){
        int thickness = 2;
        int lineType = 8;
        int shift = 0;

        line(img,
                start,
                end,
                new Scalar(0,0,0),
                thickness,
                lineType,
                shift);
    }
  • 如我们看到的,MyLine 仅仅只是简单的调用了line()方法,并传入如下参数:
  • 线段所要绘制的图像
  • 所要绘制线段的起点位置以及终点位置
  • 线段的颜色,本例用new Scalar(0,0,0),绘制一条黑色的线段
  • 线段的粗细thickness
  • 以及线型lineType ,lineType=8指的是8联通线型
MyEllipse
private static void MyEllipse(Mat img, double angle){
        int thickness = 2;
        int lineType = 8;
        int shift = 0;
        ellipse(img,
                new Point(W/2,W/2),
                new Size(W/4,W/16),
                angle,
                0.0,
                360.0,
                new Scalar(255,0,0),
                thickness,
                lineType,
                shift);
    }
  • 从上述代码中我们可以看出ellipse()方法绘制一个如下参数的椭圆:
  • 椭圆的显示图像img
  • 椭圆的中心位置new Point(W/2,W/2),以及椭圆所在的框的大小new Size(W/4,W/16)
  • 椭圆的旋转角度angle
  • 椭圆绘制的弧度范围0,360
  • 绘制的线条的颜色 new Scalar(255,0,0)
  • 粗细thickness
  • 线型lineType=8
  • shift参数,是将坐标的小数点向前移动几位。
MyFilledCircle
public static  void MyFilledCircle(Mat img,Point center){
        int thickness = 2;
        int lineType = 8;
        int shift = 0;
        circle(img,
                center,
                W/32,
                new Scalar(0,0,255),
                thickness,
                lineType,
                shift);
    }
  • 类似于上述的ellipse方法,circle方法包含如下参数:
  • 所要显示圆的图像img
  • 绘制圆的中心坐标center
  • 圆的半径W/32
  • 绘制圆的颜色new Scalar(0,0,255),
  • 粗细thickness
  • 线型lineType=8
  • shift参数,是将坐标的小数点向前移动几位。
MyPolygon
private static void MyPolygon(Mat img){
        int lineType = 8;
        int shift = 0;
        Point[] rook_points = new Point[20];
        rook_points[0]  = new Point(     W/4, 7*W/8   );
        rook_points[1]  = new Point(   3*W/4, 7*W/8   );
        rook_points[2]  = new Point(   3*W/4, 13*W/16 );
        rook_points[3]  = new Point( 11*W/16, 13*W/16 );
        rook_points[4]  = new Point( 19*W/32, 3*W/8   );
        rook_points[5]  = new Point(   3*W/4, 3*W/8   );
        rook_points[6]  = new Point(   3*W/4, W/8     );
        rook_points[7]  = new Point( 26*W/40, W/8     );
        rook_points[8]  = new Point( 26*W/40, W/4     );
        rook_points[9]  = new Point( 22*W/40, W/4     );
        rook_points[10] = new Point( 22*W/40, W/8     );
        rook_points[11] = new Point( 18*W/40, W/8     );
        rook_points[12] = new Point( 18*W/40, W/4     );
        rook_points[13] = new Point( 14*W/40, W/4     );
        rook_points[14] = new Point( 14*W/40, W/8     );
        rook_points[15] = new Point(     W/4, W/8     );
        rook_points[16] = new Point(     W/4, 3*W/8   );
        rook_points[17] = new Point( 13*W/32, 3*W/8   );
        rook_points[18] = new Point(  5*W/16, 13*W/16 );
        rook_points[19] = new Point(     W/4, 13*W/16 );
        MatOfPoint matPt = new MatOfPoint();
        matPt.fromArray(rook_points);
        ArrayList<MatOfPoint> ppt = new ArrayList<>();
        ppt.add(matPt);
        fillPoly(img,
                ppt,
                new Scalar(255,255,255),
                lineType,
                shift,
                new Point(0,0));
    }
  • 我们使用fillPoly绘制一个多边形。
  • 绘制的图像容器img
  • 包含多边形顶点的Point集合ppt
  • 多边形填充的颜色new Scalar(255,255,255),代表白色
rectangle
rectangle(rook_image,
                new Point(0,7*W/8),
                new Point(W,W),
                new Scalar(0,255,255),
                -1,
                8,
                0);
  • 最后我们直接调用cv::rectangle方法绘制矩形:
  • 矩形将绘制在rook_image中
  • 两个对角线顶点坐标分别定义 new Point(0,7*W/8), new Point(W,W),
  • 矩形的颜色new Scalar(0,255,255),
  • 由于thickness 值=-1 因此矩形将被填充

结果

编译运行代码我们回得到如下图像:

opencv画地形图 opencv绘制点_opencv