001package org.openimaj.processing; 002 003import java.util.ArrayList; 004import java.util.List; 005 006import org.openimaj.image.MBFImage; 007import org.openimaj.image.processing.face.detection.DetectedFace; 008import org.openimaj.image.processing.face.detection.HaarCascadeDetector; 009import org.openimaj.image.processing.resize.ResizeProcessor; 010import org.openimaj.math.geometry.shape.Rectangle; 011import org.openimaj.video.capture.VideoCapture; 012import org.openimaj.video.capture.VideoCaptureException; 013 014import processing.core.PApplet; 015import processing.core.PConstants; 016import processing.core.PImage; 017import processing.core.PShape; 018 019/** 020 * @author Sina Samangooei (ss@ecs.soton.ac.uk) 021 * 022 */ 023public class OpenIMAJ implements PConstants{ 024 025 private static final int DEFAULT_WIDTH = 640; 026 private static final int DEFAULT_HEIGHT = 480; 027 PApplet parent; 028 private MBFImage oiImage; 029 private HaarCascadeDetector faceDetector; 030 private VideoCapture capture; 031 032 /** 033 * @param parent 034 */ 035 public OpenIMAJ(PApplet parent) { 036 this(); 037 this.parent = parent; 038 039 parent.registerMethod("dispose", this); 040 parent.registerMethod("pre", this); 041 } 042 043 /** 044 * 045 */ 046 public OpenIMAJ() { 047 faceDetector = new HaarCascadeDetector(80); 048 } 049 050 /** 051 * Initialise face detection with minimum face size 052 * @param min 053 */ 054 public void initFace(int min){ 055 faceDetector = new HaarCascadeDetector(min); 056 } 057 058 /** 059 * Start a video capture, default size, default device 060 */ 061 public void startCapture(){ 062 try { 063 this.capture = new VideoCapture(DEFAULT_WIDTH, DEFAULT_HEIGHT); 064 } catch (VideoCaptureException e) { 065 } 066 } 067 068 /** 069 * Initialise video capture on the default device 070 * 071 * @param width 072 * @param height 073 */ 074 public void startCapture(int width, int height){ 075 try { 076 this.capture = new VideoCapture(width, height); 077 } catch (VideoCaptureException e) { 078 } 079 } 080 /** 081 * Initialise video capture 082 * 083 * @param width 084 * @param height 085 * @param device 086 */ 087 public void startCapture(int width, int height, int device){ 088 try { 089 this.capture = new VideoCapture(width, height,VideoCapture.getVideoDevices().get(device)); 090 } catch (VideoCaptureException e) { 091 } 092 } 093 094 /** 095 * Given an initialised video capture, capture a {@link PImage} 096 * @return capture 097 */ 098 public PImage capturePImage(){ 099 MBFImage frame = this.capture.getNextFrame(); 100 return asPImage(frame); 101 } 102 /** 103 * Given an initialised video capture, capture a {@link PImage} 104 * @param setToCurrentFrame whether the current openimaj frame (for analysis) should be set from capture 105 * @return capture 106 */ 107 public PImage capturePImage(boolean setToCurrentFrame){ 108 109 MBFImage frame = this.capture.getNextFrame(); 110 if(setToCurrentFrame){ 111 this.oiImage = frame.clone(); 112 } 113 return asPImage(frame); 114 } 115 116 /** 117 * Capture an {@link MBFImage} 118 * @return 119 */ 120 public MBFImage capture(){ 121 MBFImage frame = this.capture.getNextFrame(); 122 return frame; 123 } 124 public MBFImage capture(boolean setToCurrentFrame){ 125 126 MBFImage frame = this.capture.getNextFrame(); 127 if(setToCurrentFrame){ 128 this.oiImage = frame.clone(); 129 } 130 return frame; 131 } 132 133 public PImage asPImage(MBFImage frame) { 134 PImage img = this.parent.createImage(frame.getWidth(), frame.getHeight(), RGB); 135 img.pixels = frame.toPackedARGBPixels(); 136 return img; 137 } 138 139 /** 140 * 141 */ 142 public void pre(){ 143 } 144 /** 145 * Updates the OpenIMAJ held {@link MBFImage} instance from the whole parent {@link PApplet} 146 */ 147 public void updateImage() { 148 this.parent.loadPixels(); 149 updateImage(this.parent.pixels,this.parent.width,this.parent.height); 150 } 151 152 /** 153 * @param capture 154 */ 155 public void updateImage(PImage capture){ 156 updateImage(capture.pixels,capture.width, capture.height); 157 } 158 159 /** 160 * @param capture 161 */ 162 public void updateImage(MBFImage capture){ 163 this.oiImage = capture; 164 } 165 166 /** 167 * Updates the OpenIMAJ held {@link MBFImage} instance 168 * @param pixels the pixels to use as the MBFImage 169 * @param width the width of the image 170 * @param height the height of the image 171 */ 172 public void updateImage(int[] pixels,int width, int height) { 173 this.oiImage = new MBFImage(pixels,width, height); 174 } 175 /** 176 * 177 */ 178 public void dispose() { 179 this.oiImage = null; 180 } 181 182 public void resize(int width, int height){ 183 if(this.oiImage == null) return; 184 this.oiImage.processInplace(new ResizeProcessor(width, height)); 185 } 186 187 /** 188 * Detect faces using {@link HaarCascadeDetector}, return an {@link ArrayList} of 189 * {@link PShape} instances. Note the {@link PShape} instances have no fill and 190 * a colour: 255,0,0 191 * @return detected faces 192 */ 193 public ArrayList<PShape> faces(){ 194 ArrayList<PShape> faces = new ArrayList<PShape>(); 195 List<DetectedFace> detected = faceDetector.detectFaces(oiImage.flatten()); 196 for (DetectedFace detectedFace : detected) { 197 Rectangle bounds = detectedFace.getBounds(); 198 PShape detectedPShape = this.parent.createShape(RECT,bounds.x,bounds.y,bounds.width,bounds.height); 199 200 detectedPShape.setFill(false); 201 detectedPShape.setStroke(this.parent.color(255f, 0, 0)); 202 faces.add(detectedPShape); 203 } 204 return faces; 205 } 206}