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 org.photonvision.common.util.numbers.IntegerCouple; 021import org.photonvision.vision.frame.Frame; 022import org.photonvision.vision.frame.FrameProvider; 023import org.photonvision.vision.frame.FrameStaticProperties; 024import org.photonvision.vision.frame.FrameThresholdType; 025import org.photonvision.vision.opencv.CVMat; 026import org.photonvision.vision.opencv.ImageRotationMode; 027import org.photonvision.vision.pipe.CVPipe.CVPipeResult; 028import org.photonvision.vision.pipe.impl.GrayscalePipe; 029import org.photonvision.vision.pipe.impl.HSVPipe; 030import org.photonvision.vision.pipe.impl.RotateImagePipe; 031 032public abstract class CpuImageProcessor extends FrameProvider { 033 protected static class CapturedFrame { 034 CVMat colorImage; 035 FrameStaticProperties staticProps; 036 long captureTimestamp; 037 038 public CapturedFrame( 039 CVMat colorImage, FrameStaticProperties staticProps, long captureTimestampNanos) { 040 this.colorImage = colorImage; 041 this.staticProps = staticProps; 042 this.captureTimestamp = captureTimestampNanos; 043 } 044 } 045 046 private final HSVPipe m_hsvPipe = new HSVPipe(); 047 private final RotateImagePipe m_rImagePipe = new RotateImagePipe(); 048 private final GrayscalePipe m_grayPipe = new GrayscalePipe(); 049 FrameThresholdType m_processType; 050 051 private final Object m_mutex = new Object(); 052 053 abstract CapturedFrame getInputMat(); 054 055 public CpuImageProcessor() { 056 m_hsvPipe.setParams( 057 new HSVPipe.HSVParams( 058 new IntegerCouple(0, 180), 059 new IntegerCouple(0, 255), 060 new IntegerCouple(0, 255), 061 false)); 062 } 063 064 @Override 065 public final Frame get() { 066 // TODO Auto-generated method stub 067 var input = getInputMat(); 068 069 CVMat outputMat = null; 070 long sumNanos = 0; 071 072 { 073 CVPipeResult<Void> out = m_rImagePipe.run(input.colorImage.getMat()); 074 sumNanos += out.nanosElapsed; 075 } 076 077 if (!input.colorImage.getMat().empty()) { 078 if (m_processType == FrameThresholdType.HSV) { 079 var hsvResult = m_hsvPipe.run(input.colorImage.getMat()); 080 outputMat = new CVMat(hsvResult.output); 081 sumNanos += hsvResult.nanosElapsed; 082 } else if (m_processType == FrameThresholdType.GREYSCALE) { 083 var result = m_grayPipe.run(input.colorImage.getMat()); 084 outputMat = new CVMat(result.output); 085 sumNanos += result.nanosElapsed; 086 } else { 087 outputMat = new CVMat(); 088 } 089 090 ++sequenceID; 091 } else { 092 System.out.println("Input was empty!"); 093 outputMat = new CVMat(); 094 } 095 096 return new Frame( 097 sequenceID, 098 input.colorImage, 099 outputMat, 100 m_processType, 101 input.captureTimestamp, 102 input.staticProps != null 103 ? input.staticProps.rotate(m_rImagePipe.getParams().rotation) 104 : input.staticProps); 105 } 106 107 @Override 108 public void requestFrameThresholdType(FrameThresholdType type) { 109 synchronized (m_mutex) { 110 this.m_processType = type; 111 } 112 } 113 114 @Override 115 public void requestFrameRotation(ImageRotationMode rotationMode) { 116 synchronized (m_mutex) { 117 m_rImagePipe.setParams(new RotateImagePipe.RotateImageParams(rotationMode)); 118 } 119 } 120 121 /** Ask the camera to rotate frames it outputs */ 122 public void requestHsvSettings(HSVPipe.HSVParams params) { 123 synchronized (m_mutex) { 124 m_hsvPipe.setParams(params); 125 } 126 } 127 128 @Override 129 public void requestFrameCopies(boolean copyInput, boolean copyOutput) { 130 // We don't actually do zero-copy, so this method is a no-op 131 } 132}