001/*
002 * Copyright (C) Photon Vision.
003 *
004 * This program is free software: you can redistribute it and/or modify
005 * it under the terms of the GNU General Public License as published by
006 * the Free Software Foundation, either version 3 of the License, or
007 * (at your option) any later version.
008 *
009 * This program is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012 * GNU General Public License for more details.
013 *
014 * You should have received a copy of the GNU General Public License
015 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
016 */
017
018package org.photonvision.vision.calibration;
019
020import com.fasterxml.jackson.annotation.JsonIgnore;
021import com.fasterxml.jackson.annotation.JsonProperty;
022import java.util.Base64;
023import org.opencv.core.Mat;
024import org.opencv.core.MatOfByte;
025import org.opencv.imgcodecs.Imgcodecs;
026import org.photonvision.vision.opencv.Releasable;
027
028/** JSON-serializable image. Data is stored as base64-encoded PNG data. */
029public class JsonImageMat implements Releasable {
030    public final int rows;
031    public final int cols;
032    public final int type;
033
034    // We store image data as a base64-encoded PNG inside a Java string. This lets us serialize it
035    // without too much overhead and still use JSON.
036    public final String data;
037
038    // Cached matrices to avoid object recreation
039    @JsonIgnore private Mat wrappedMat = null;
040
041    public JsonImageMat(Mat mat) {
042        this.rows = mat.rows();
043        this.cols = mat.cols();
044        this.type = mat.type();
045
046        // Convert from Mat -> png byte array -> base64
047        var buf = new MatOfByte();
048        Imgcodecs.imencode(".png", mat, buf);
049        data = Base64.getEncoder().encodeToString(buf.toArray());
050        buf.release();
051    }
052
053    public JsonImageMat(
054            @JsonProperty("rows") int rows,
055            @JsonProperty("cols") int cols,
056            @JsonProperty("type") int type,
057            @JsonProperty("data") String data) {
058        this.rows = rows;
059        this.cols = cols;
060        this.type = type;
061        this.data = data;
062    }
063
064    @JsonIgnore
065    public Mat getAsMat() {
066        if (wrappedMat == null) {
067            // Convert back from base64 string -> png -> Mat
068            var bytes = Base64.getDecoder().decode(data);
069            var pngData = new MatOfByte(bytes);
070            this.wrappedMat = Imgcodecs.imdecode(pngData, Imgcodecs.IMREAD_COLOR);
071        }
072        return this.wrappedMat;
073    }
074
075    @Override
076    public void release() {
077        if (wrappedMat != null) wrappedMat.release();
078    }
079
080    @Override
081    public String toString() {
082        return "JsonImageMat [rows="
083                + rows
084                + ", cols="
085                + cols
086                + ", type="
087                + type
088                + ", datalen="
089                + data.length()
090                + "]";
091    }
092}