001// Copyright (c) FIRST and other WPILib contributors. 002// Open Source Software; you can modify and/or share it under the terms of 003// the WPILib BSD license file in the root directory of this project. 004 005package edu.wpi.first.cscore; 006 007import edu.wpi.first.util.PixelFormat; 008import org.opencv.core.Mat; 009 010/** 011 * A source that represents a video camera. These sources require the WPILib OpenCV builds. For an 012 * alternate OpenCV, see the documentation how to build your own with RawSource. 013 */ 014public class CvSource extends ImageSource { 015 /** 016 * Create an OpenCV source. 017 * 018 * @param name Source name (arbitrary unique identifier) 019 * @param mode Video mode being generated 020 */ 021 public CvSource(String name, VideoMode mode) { 022 super( 023 CameraServerJNI.createRawSource( 024 name, true, mode.pixelFormat.getValue(), mode.width, mode.height, mode.fps)); 025 OpenCvLoader.forceStaticLoad(); 026 } 027 028 /** 029 * Create an OpenCV source. 030 * 031 * @param name Source name (arbitrary unique identifier) 032 * @param pixelFormat Pixel format 033 * @param width width 034 * @param height height 035 * @param fps fps 036 */ 037 public CvSource(String name, PixelFormat pixelFormat, int width, int height, int fps) { 038 super(CameraServerJNI.createRawSource(name, true, pixelFormat.getValue(), width, height, fps)); 039 OpenCvLoader.forceStaticLoad(); 040 } 041 042 /** 043 * Put an OpenCV image and notify sinks 044 * 045 * <p>The image format is guessed from the number of channels. The channel mapping is as follows. 046 * 1: kGray 2: kYUYV 3: BGR 4: BGRA Any other channel numbers will throw an error. If your image 047 * is an in alternate format, use the overload that takes a PixelFormat. 048 * 049 * @param image OpenCV Image 050 */ 051 public void putFrame(Mat image) { 052 // We only support 8 bit channels 053 boolean cleanupRequired = false; 054 Mat finalImage; 055 if (image.depth() == 0) { 056 finalImage = image; 057 } else { 058 finalImage = new Mat(); 059 image.convertTo(finalImage, 0); 060 cleanupRequired = true; 061 } 062 063 try { 064 int channels = finalImage.channels(); 065 PixelFormat format; 066 if (channels == 1) { 067 // 1 channel is assumed Graysacle 068 format = PixelFormat.kGray; 069 } else if (channels == 2) { 070 // 2 channels is assumed YUYV 071 format = PixelFormat.kYUYV; 072 } else if (channels == 3) { 073 // 3 channels is assumed BGR 074 format = PixelFormat.kBGR; 075 } else if (channels == 4) { 076 // 4 channels is assumed BGRA 077 format = PixelFormat.kBGRA; 078 } else { 079 throw new VideoException("Unable to get pixel format for " + channels + " channels"); 080 } 081 082 putFrame(finalImage, format, true); 083 } finally { 084 if (cleanupRequired) { 085 finalImage.release(); 086 } 087 } 088 } 089 090 /** 091 * Put an OpenCV image and notify sinks. 092 * 093 * <p>The format of the Mat must match the PixelFormat. You will corrupt memory if they dont. With 094 * skipVerification false, we will verify the number of channels matches the pixel format. If 095 * skipVerification is true, this step is skipped and is passed straight through. 096 * 097 * @param image OpenCV image 098 * @param format The pixel format of the image 099 * @param skipVerification skip verifying pixel format 100 */ 101 public void putFrame(Mat image, PixelFormat format, boolean skipVerification) { 102 // We only support 8-bit images, convert if necessary 103 boolean cleanupRequired = false; 104 Mat finalImage; 105 if (image.depth() == 0) { 106 finalImage = image; 107 } else { 108 finalImage = new Mat(); 109 image.convertTo(finalImage, 0); 110 cleanupRequired = true; 111 } 112 113 try { 114 if (!skipVerification) { 115 verifyFormat(finalImage, format); 116 } 117 long step = image.step1() * image.elemSize1(); 118 CameraServerJNI.putRawSourceFrameData( 119 m_handle, 120 finalImage.dataAddr(), 121 (int) finalImage.total() * finalImage.channels(), 122 finalImage.width(), 123 finalImage.height(), 124 (int) step, 125 format.getValue()); 126 127 } finally { 128 if (cleanupRequired) { 129 finalImage.release(); 130 } 131 } 132 } 133 134 private void verifyFormat(Mat image, PixelFormat pixelFormat) { 135 int channels = image.channels(); 136 switch (pixelFormat) { 137 case kBGR: 138 if (channels == 3) { 139 return; 140 } 141 break; 142 case kBGRA: 143 if (channels == 4) { 144 return; 145 } 146 break; 147 case kGray: 148 if (channels == 1) { 149 return; 150 } 151 break; 152 case kRGB565: 153 if (channels == 2) { 154 return; 155 } 156 break; 157 case kUYVY: 158 if (channels == 2) { 159 return; 160 } 161 break; 162 case kY16: 163 if (channels == 2) { 164 return; 165 } 166 break; 167 case kYUYV: 168 if (channels == 2) { 169 return; 170 } 171 break; 172 case kMJPEG: 173 if (channels == 1) { 174 return; 175 } 176 break; 177 default: 178 break; 179 } 180 } 181}