Opencv java to achieve basic graphics operations

Opencv java to achieve basic graphics operations

This is the second blog I came up with after I finished my image processing homework. In the last issue, I briefly introduced how to use opencv in the springboot environment. In this issue, I will continue to briefly talk about the basic operation of OpenCV in Java version.

In my understanding, the basic operations of opencv are almost rotation, horizontal mirror, flip, zoom in and out, clipping and drawing, etc. They are all operations without any technical content. Most of them can be completed by calling functions. Students with opencv foundation can certainly master them quickly.

However, before the explanation, there is one point that needs to be discussed with you in advance, that is, the encapsulation of several core libraries in java version opencv, and only cv is required in c version OpenCV You can call all kinds of functions, but some of them are repackaged in java (most of them remain the same).

Core is still the core function module, especially the underlying data structure and algorithm functions, such as Mat, core, etc.
imgproc, image processing module, basically all the image processing functions that need to be used are in this.
highgui, a high-level GUI display module, provides graphics and media interfaces. The commonly used imshow is inside.
imgcodecs, I don't know what this library means, but imread is encapsulated in it.
calib3d, camera calibration and 3D reconstruction.
features2d, 2D functional framework, including point of interest detector, descriptor and point of interest matching framework.
ml, machine learning module.
objdetect, object detection module.
Video, video analysis component.

Of course, a lot has been introduced above. In fact, only imgcodecs library is repackaged. The rest seem to be no different from opencv. It does not rule out that imgcodecs already exists in the new version of opencv, because I use 3 X, at least not at that time. For basic image processing, the actual need is to introduce three libraries at the beginning.

Since I use SpringBoot to separate the front and rear end of a single room, I need to convert the image into Base64 format and send it to the front-end React after processing and packaging it into Mat, The following code will involve several functions [Mat to image and then to bufferedimage]. Bufferedimage is java's own image saving format, which is similar to the variable area in matlab, and can save some basic information of images. The two conversion functions here have been verified and can be used directly. They are very simple to write and can be fine tuned according to actual needs.

public class Converter {

    public static Map<String,Object> BufferedImageToBase64(BufferedImage bufferedImage) throws IOException {
        Map<String,Object> result = new HashMap<>();
        //Convert the picture into a string to the front end
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        ImageIO.write(bufferedImage, "png", stream);

        Base64.Encoder encoder = Base64.getEncoder();
        String base64 = encoder.encodeToString(stream.toByteArray());

        stream.flush();
        stream.close();
        //Encapsulate data

        result.put("image", "data:image/png;base64,"+base64);
        return result;
    }

    public static BufferedImage ImageToBufferedImage(Image image){
        if (image instanceof BufferedImage) {
            return (BufferedImage)image;
        }
        image = new ImageIcon(image).getImage();
        BufferedImage bimage = null;
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        try {
            int transparency = Transparency.OPAQUE;
            GraphicsDevice gs = ge.getDefaultScreenDevice();
            GraphicsConfiguration gc = gs.getDefaultConfiguration();
            bimage = gc.createCompatibleImage(
                    image.getWidth(null), image.getHeight(null), transparency);
        } catch (HeadlessException e) {
        }

        if (bimage == null) {
            int type = BufferedImage.TYPE_INT_RGB;
            bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
        }
        Graphics g = bimage.createGraphics();

        g.drawImage(image, 0, 0, null);
        g.dispose();

        return bimage;
    }
}

Picture reading

My picture reading uses the swing component to call the file selector. The simple painting doesn't need to be so complex. Just pass the required file path directly. As for the simple system components, I'll talk about them in the next few issues.

@PostMapping("open")
public Map<String,Object> open(HttpServletResponse response) throws IOException {

    response.setContentType("application/octet-stream; charset=utf-8");
    response.setContentType("image/png");

    /*Open file selector*/
    FileChooser f = new FileChooser();
    String imgPath = f.getPath();
    System.out.println(imgPath);

    /*Convert to BufferedImage*/
    BufferedImage read = ImageIO.read(new FileInputStream(imgPath));

    /*Save one to OpenCV*/
    MatImage.matImage=imread(imgPath);
    History.AllMethod(MatImage.matImage);
    System.out.println(MatImage.matImage);

    /*Package base64 to front end*/
    return Converter.BufferedImageToBase64(read);
}

The above code is the specific writing method in my controller. I read it twice because it needs to be sent to the front-end display. In fact, the best writing method is the first time Mat reads it, After reading it, it is directly saved in the back-end for backup (so that the front-end does not need to send the pictures to be operated to the back-end. After the back-end operation is completed, it is OK to let the front-end display). After the backup is completed, it is directly said to transfer Mat to base64 and send it. My writing method above is bloated.

If you want to read and display directly, this writing method is enough

Mat image = Imgcodecs.imread("D:/test.bmp");
HighGui.imshow("yt",image);
HighGui.waitKey(13);

imshow is a separate small window. If it is a web project, it is recommended to refer to the above to modify the first code.

rotate

Rotate any angle

/**
    * Rotate counterclockwise, but the width and height of the picture do not change. This method is incompatible with rotateLeft and rotateRight
    *
    * @param src    source
    * @param angele Angle of rotation
    * @return Rotated object
    */
public static Mat rotate(Mat src, double angele) {
    Mat dst = src.clone();
    org.opencv.core.Point center = new org.opencv.core.Point(src.width() / 2.0, src.height() / 2.0);
    Mat affineTrans = Imgproc.getRotationMatrix2D(center, angele, 1.0);
    Imgproc.warpAffine(src, dst, affineTrans, dst.size(), Imgproc.INTER_NEAREST);
    return dst;
}

Rotate 90 °, flip vertically and horizontally

@RequestMapping("spin")
public Map<String,Object> spin(HttpServletResponse response,
                                @RequestParam("key") String key) throws IOException {

    response.setContentType("application/octet-stream; charset=utf-8");
    response.setContentType("image/png");

    /*Take Mat from constants*/
    Mat mat = MatImage.matImage;
    Mat temp = new Mat();
    Mat result = new Mat();

    switch (key) {
        case "0": {

            /*Clockwise 90*/
            Core.transpose(mat, temp);
            Core.flip(temp, result, 1);

            /*Change stored pictures*/
            MatImage.matImage = result;
            History.AllMethod(MatImage.matImage);

            Image image = toBufferedImage(result);
            BufferedImage bufferedImage = Converter.ImageToBufferedImage(image);
            return Converter.BufferedImageToBase64(bufferedImage);
        }
        case "1": {

            /*Counterclockwise 90*/
            Core.transpose(mat, temp);
            Core.flip(temp, result, 0);

            /*Change stored pictures*/
            MatImage.matImage = result;
            History.AllMethod(MatImage.matImage);

            Image image = toBufferedImage(result);
            BufferedImage bufferedImage = Converter.ImageToBufferedImage(image);
            return Converter.BufferedImageToBase64(bufferedImage);
        }
        case "2": {

            /*Turn 180*/

            Core.flip(mat, result, -1);
            /*Change stored pictures*/
            MatImage.matImage = result;
            History.AllMethod(MatImage.matImage);

            Image image = toBufferedImage(result);
            BufferedImage bufferedImage = Converter.ImageToBufferedImage(image);
            return Converter.BufferedImageToBase64(bufferedImage);
        }
        case "3":{

            /*Flip horizontally*/
            Core.flip(mat,result,1);

            MatImage.matImage=result;
            History.AllMethod(MatImage.matImage);

            Image image = toBufferedImage(result);
            BufferedImage bufferedImage = Converter.ImageToBufferedImage(image);
            return Converter.BufferedImageToBase64(bufferedImage);

        }
        case "4":{
            /*Flip vertically*/
            Core.flip(mat,result,0);

            MatImage.matImage=result;
            History.AllMethod(MatImage.matImage);

            Image image = toBufferedImage(result);
            BufferedImage bufferedImage = Converter.ImageToBufferedImage(image);
            return Converter.BufferedImageToBase64(bufferedImage);
        }
        default:
            return null;
    }
}

The above is the writing method in springboot, which is also easy to understand when translated into ordinary maven. Pick out the contents of a random case and remove the core Delete everything after flip and add imshow and waitkey.

Because what is actually needed is the flip in the Core. The accepted parameters are mat (need to operate the picture), res (output picture) and type (operation method). When the third parameter type is 0, it is 90 ° clockwise and 1 is 90 ° counterclockwise. Then, it is easy to understand the truth and what to do with the transfer rotation.

Cutting

Rect rect = new Rect(x,y,ex-x,ey-y);
Mat result = new Mat(mat,rect);

Rect is the content encapsulated in the core and represents a rectangular box. Here, the coordinates, width and height of the first point in the upper left corner are entered. After passing in Mat, clipping can be realized. In fact, an object is redefined, but its scope is limited.

When it comes to clipping, I have to talk about the front-end technology. Here is also the manual clipping box that I have referenced many documents and tutorials, which is implemented based on React and js.

Keywords: Java OpenCV AI

Added by fanfavorite on Sat, 25 Dec 2021 07:54:43 +0200