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.frame.provider; 019 020import java.nio.file.Files; 021import java.nio.file.Path; 022import java.nio.file.Paths; 023import org.opencv.core.Mat; 024import org.opencv.imgcodecs.Imgcodecs; 025import org.photonvision.common.util.math.MathUtils; 026import org.photonvision.vision.calibration.CameraCalibrationCoefficients; 027import org.photonvision.vision.frame.FrameProvider; 028import org.photonvision.vision.frame.FrameStaticProperties; 029import org.photonvision.vision.opencv.CVMat; 030import org.photonvision.vision.opencv.Releasable; 031 032/** 033 * A {@link FrameProvider} that will read and provide an image from a {@link java.nio.file.Path 034 * path}. 035 */ 036public class FileFrameProvider extends CpuImageProcessor implements Releasable { 037 public static final int MAX_FPS = 10; 038 private static int count = 0; 039 040 private final int thisIndex = count++; 041 private final Path path; 042 private final int millisDelay; 043 private final CVMat originalFrame; 044 045 private final FrameStaticProperties properties; 046 047 private long lastGetMillis = System.currentTimeMillis(); 048 049 /** 050 * Instantiates a new FileFrameProvider. 051 * 052 * @param path The path of the image to read from. 053 * @param fov The fov of the image. 054 * @param maxFPS The max framerate to provide the image at. 055 */ 056 public FileFrameProvider(Path path, double fov, int maxFPS) { 057 this(path, fov, maxFPS, null); 058 } 059 060 public FileFrameProvider(Path path, double fov, CameraCalibrationCoefficients calibration) { 061 this(path, fov, MAX_FPS, calibration); 062 } 063 064 public FileFrameProvider( 065 Path path, double fov, int maxFPS, CameraCalibrationCoefficients calibration) { 066 if (!Files.exists(path)) 067 throw new RuntimeException("Invalid path for image: " + path.toAbsolutePath()); 068 this.path = path; 069 this.millisDelay = 1000 / maxFPS; 070 071 Mat rawImage = Imgcodecs.imread(path.toString()); 072 if (rawImage.cols() > 0 && rawImage.rows() > 0) { 073 properties = new FrameStaticProperties(rawImage.width(), rawImage.height(), fov, calibration); 074 originalFrame = new CVMat(rawImage); 075 } else { 076 throw new RuntimeException("Image loading failed!"); 077 } 078 } 079 080 /** 081 * Instantiates a new File frame provider. 082 * 083 * @param pathAsString The path of the image to read from as a string. 084 * @param fov The fov of the image. 085 */ 086 public FileFrameProvider(String pathAsString, double fov) { 087 this(Paths.get(pathAsString), fov, MAX_FPS); 088 } 089 090 /** 091 * Instantiates a new File frame provider. 092 * 093 * @param path The path of the image to read from. 094 * @param fov The fov of the image. 095 */ 096 public FileFrameProvider(Path path, double fov) { 097 this(path, fov, MAX_FPS); 098 } 099 100 @Override 101 public CapturedFrame getInputMat() { 102 var out = new CVMat(); 103 out.copyFrom(originalFrame); 104 105 // block to keep FPS at a defined rate 106 if (System.currentTimeMillis() - lastGetMillis < millisDelay) { 107 try { 108 Thread.sleep(millisDelay); 109 } catch (InterruptedException e) { 110 System.err.println("FileFrameProvider interrupted - not busywaiting"); 111 // throw back up the stack 112 throw new RuntimeException(e); 113 } 114 } 115 116 lastGetMillis = System.currentTimeMillis(); 117 return new CapturedFrame(out, properties, MathUtils.wpiNanoTime()); 118 } 119 120 @Override 121 public String getName() { 122 return "FileFrameProvider" + thisIndex + " - " + path.getFileName(); 123 } 124 125 @Override 126 public void release() { 127 originalFrame.release(); 128 } 129 130 @Override 131 public boolean checkCameraConnected() { 132 return true; 133 } 134 135 @Override 136 public boolean isConnected() { 137 return true; 138 } 139 140 @Override 141 public boolean hasConnected() { 142 return true; 143 } 144}