1+ package net .ladstatt .javacv
2+
3+ import java .net .URL
4+
5+ import org .bytedeco .javacpp ._
6+ import org .bytedeco .javacpp .indexer .{DoubleRawIndexer , FloatIndexer }
7+ import org .bytedeco .javacv ._
8+ import org .bytedeco .opencv .global .opencv_calib3d ._
9+ import org .bytedeco .opencv .global .opencv_core ._
10+ import org .bytedeco .opencv .global .opencv_imgproc ._
11+ import org .bytedeco .opencv .opencv_core ._
12+ import org .bytedeco .opencv .opencv_objdetect ._
13+
14+
15+ /**
16+ * Port of the example given at bytedeco's github page:
17+ *
18+ * https://github.com/bytedeco/javacv
19+ *
20+ * to a scala version
21+ */
22+ object SwingDemo {
23+
24+ def main (args : Array [String ]): Unit = {
25+ var classifierName : String = null
26+ if (args.length > 0 ) {
27+ classifierName = args(0 )
28+ } else {
29+ val url = new URL (" https://raw.github.com/opencv/opencv/master/data/haarcascades/haarcascade_frontalface_alt.xml" )
30+ val file = Loader .cacheResource(url)
31+ classifierName = file.getAbsolutePath
32+ }
33+ // We can "cast" Pointer objects by instantiating a new object of the desired class.
34+ val classifier = new CascadeClassifier (classifierName)
35+ if (classifier == null ) {
36+ System .err.println(" Error loading classifier file \" " + classifierName + " \" ." )
37+ System .exit(1 )
38+ }
39+ // The available FrameGrabber classes include OpenCVFrameGrabber (opencv_videoio),
40+ // DC1394FrameGrabber, FlyCapture2FrameGrabber, OpenKinectFrameGrabber, OpenKinect2FrameGrabber,
41+ // RealSenseFrameGrabber, RealSense2FrameGrabber, PS3EyeFrameGrabber, VideoInputFrameGrabber, and FFmpegFrameGrabber.
42+ val grabber = FrameGrabber .createDefault(0 )
43+ grabber.start()
44+ // CanvasFrame, FrameGrabber, and FrameRecorder use Frame objects to communicate image data.
45+ // We need a FrameConverter to interface with other APIs (Android, Java 2D, JavaFX, Tesseract, OpenCV, etc).
46+ val converter = new OpenCVFrameConverter .ToMat
47+ // FAQ about IplImage and Mat objects from OpenCV:
48+ // - For custom raw processing of data, createBuffer() returns an NIO direct
49+ // buffer wrapped around the memory pointed by imageData, and under Android we can
50+ // also use that Buffer with Bitmap.copyPixelsFromBuffer() and copyPixelsToBuffer().
51+ // - To get a BufferedImage from an IplImage, or vice versa, we can chain calls to
52+ // Java2DFrameConverter and OpenCVFrameConverter, one after the other.
53+ // - Java2DFrameConverter also has static copy() methods that we can use to transfer
54+ // data more directly between BufferedImage and IplImage or Mat via Frame objects.
55+ var grabbedImage = converter.convert(grabber.grab)
56+ val height = grabbedImage.rows
57+ val width = grabbedImage.cols
58+ // Objects allocated with `new`, clone(), or a create*() factory method are automatically released
59+ // by the garbage collector, but may still be explicitly released by calling deallocate().
60+ // You shall NOT call cvReleaseImage(), cvReleaseMemStorage(), etc. on objects allocated this way.
61+ val grayImage = new Mat (height, width, CV_8UC1 )
62+ val rotatedImage = grabbedImage.clone
63+ // The OpenCVFrameRecorder class simply uses the VideoWriter of opencv_videoio,
64+ // but FFmpegFrameRecorder also exists as a more versatile alternative.
65+ val recorder = FrameRecorder .createDefault(" output.avi" , width, height)
66+ recorder.start()
67+ // CanvasFrame is a JFrame containing a Canvas component, which is hardware accelerated.
68+ // It can also switch into full-screen mode when called with a screenNumber.
69+ // We should also specify the relative monitor/camera response for proper gamma correction.
70+ val frame = new CanvasFrame (" Some Title" , CanvasFrame .getDefaultGamma / grabber.getGamma)
71+ // Let's create some random 3D rotation...
72+ val randomR : Mat = new Mat (3 , 3 , CV_64FC1 )
73+ val randomAxis : Mat = new Mat (3 , 1 , CV_64FC1 )
74+ // We can easily and efficiently access the elements of matrices and images
75+ // through an Indexer object with the set of get() and put() methods.
76+ val Ridx = randomR.asInstanceOf [AbstractMat ].createIndexer[DoubleRawIndexer ]()
77+ val axisIdx = randomAxis.asInstanceOf [AbstractMat ].createIndexer[DoubleRawIndexer ]()
78+ axisIdx.put(0L , randDouble, randDouble, randDouble)
79+ Rodrigues (randomAxis, randomR)
80+ val f = (width + height) / 2.0
81+ Ridx .put(0 , 2 , Ridx .get(0 , 2 ) * f)
82+ Ridx .put(1 , 2 , Ridx .get(1 , 2 ) * f)
83+ Ridx .put(2 , 0 , Ridx .get(2 , 0 ) / f)
84+ Ridx .put(2 , 1 , Ridx .get(2 , 1 ) / f)
85+ System .out.println(Ridx )
86+ // We can allocate native arrays using constructors taking an integer as argument.
87+ val hatPoints = new Point (3 )
88+ var x = true
89+ while (x) { // Let's try to detect some faces! but we need a grayscale image...
90+ grabbedImage = converter.convert(grabber.grab)
91+ x = frame.isVisible && ( grabbedImage != null )
92+ cvtColor(grabbedImage, grayImage, CV_BGR2GRAY )
93+ val faces = new RectVector
94+ classifier.detectMultiScale(grayImage, faces)
95+ val total = faces.size.toInt
96+ for (i <- 0 until total) {
97+ val r = faces.get(i)
98+ val x = r.x
99+ val y = r.y
100+ val w = r.width
101+ val h = r.height
102+ rectangle(grabbedImage, new Point (x, y), new Point (x + w, y + h), AbstractScalar .RED , 1 , CV_AA , 0 )
103+ // To access or pass as argument the elements of a native array, call position() before.
104+ hatPoints.position(0 ).x(x - w / 10 ).y(y - h / 10 )
105+ hatPoints.position(1 ).x(x + w * 11 / 10 ).y(y - h / 10 )
106+ hatPoints.position(2 ).x(x + w / 2 ).y(y - h / 2 )
107+ fillConvexPoly(grabbedImage, hatPoints.position(0 ), 3 , AbstractScalar .GREEN , CV_AA , 0 )
108+ }
109+ // Let's find some contours! but first some thresholding...
110+ threshold(grayImage, grayImage, 64 , 255 , CV_THRESH_BINARY )
111+ // To check if an output argument is null we may call either isNull() or equals(null).
112+ val contours = new MatVector
113+ findContours(grayImage, contours, CV_RETR_LIST , CV_CHAIN_APPROX_SIMPLE )
114+ val n = contours.size.toInt
115+ for (i <- 0 until n) {
116+ val contour = contours.get(i)
117+ val points = new Mat
118+ approxPolyDP(contour, points, arcLength(contour, true ) * 0.02 , true )
119+ drawContours(grabbedImage, new MatVector (points), - 1 , AbstractScalar .BLUE )
120+ }
121+ warpPerspective(grabbedImage, rotatedImage, randomR, rotatedImage.size)
122+ val rotatedFrame = converter.convert(rotatedImage)
123+ frame.showImage(rotatedFrame)
124+ recorder.record(rotatedFrame)
125+
126+
127+ }
128+ frame.dispose()
129+ recorder.stop()
130+ grabber.stop()
131+ }
132+
133+ private def randDouble : Double = {
134+ (Math .random - 0.5 ) / 4
135+ }
136+
137+ }
0 commit comments