Skip to content

Commit 4a0d1f2

Browse files
committed
Initial commit
0 parents  commit 4a0d1f2

File tree

2 files changed

+254
-0
lines changed

2 files changed

+254
-0
lines changed

pom.xml

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
<groupId>net.ladstatt.javacv</groupId>
5+
<artifactId>javacv-webcam</artifactId>
6+
<version>2020.2-SNAPSHOT</version>
7+
8+
<name>net.ladstatt.javacv.javacv-webcam</name>
9+
10+
<packaging>jar</packaging>
11+
12+
<properties>
13+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
14+
<scala.major.version>2.13</scala.major.version>
15+
<scala.full.version>${scala.major.version}.2</scala.full.version>
16+
</properties>
17+
18+
<dependencies>
19+
<dependency>
20+
<groupId>org.scala-lang</groupId>
21+
<artifactId>scala-library</artifactId>
22+
<version>${scala.full.version}</version>
23+
</dependency>
24+
<dependency>
25+
<groupId>org.bytedeco</groupId>
26+
<artifactId>javacv-platform</artifactId>
27+
<version>1.5.3</version>
28+
</dependency>
29+
</dependencies>
30+
<build>
31+
<plugins>
32+
<plugin>
33+
<groupId>net.alchim31.maven</groupId>
34+
<artifactId>scala-maven-plugin</artifactId>
35+
<version>4.3.1</version>
36+
<executions>
37+
<execution>
38+
<goals>
39+
<goal>compile</goal>
40+
<goal>testCompile</goal>
41+
</goals>
42+
</execution>
43+
</executions>
44+
<configuration>
45+
<scalaVersion>${scala.major.version}</scalaVersion>
46+
<args>
47+
<arg>-deprecation</arg>
48+
<arg>-encoding</arg>
49+
<arg>utf-8</arg>
50+
<arg>-explaintypes</arg>
51+
<arg>-feature</arg>
52+
<arg>-language:existentials</arg>
53+
<arg>-language:experimental.macros</arg>
54+
<arg>-language:higherKinds</arg>
55+
<arg>-language:implicitConversions</arg>
56+
<arg>-unchecked</arg>
57+
<arg>-Xcheckinit</arg>
58+
<arg>-Xlint:adapted-args</arg>
59+
<arg>-Xlint:constant</arg>
60+
<arg>-Xlint:delayedinit-select</arg>
61+
<arg>-Xlint:doc-detached</arg>
62+
<arg>-Xlint:inaccessible</arg>
63+
<arg>-Xlint:infer-any</arg>
64+
<arg>-Xlint:missing-interpolator</arg>
65+
<arg>-Xlint:nullary-override</arg>
66+
<arg>-Xlint:nullary-unit</arg>
67+
<arg>-Xlint:option-implicit</arg>
68+
<arg>-Xlint:package-object-classes</arg>
69+
<arg>-Xlint:poly-implicit-overload</arg>
70+
<arg>-Xlint:private-shadow</arg>
71+
<arg>-Xlint:stars-align</arg>
72+
<arg>-Xlint:type-parameter-shadow</arg>
73+
74+
<arg>-Ywarn-dead-code</arg>
75+
<arg>-Ywarn-extra-implicit</arg>
76+
<arg>-Ywarn-numeric-widen</arg>
77+
<arg>-Ywarn-unused:implicits</arg>
78+
<arg>-Ywarn-unused:imports</arg>
79+
<arg>-Ywarn-unused:locals</arg>
80+
<arg>-Ywarn-unused:params</arg>
81+
<arg>-Ywarn-unused:patvars</arg>
82+
<arg>-Ywarn-unused:privates</arg>
83+
<arg>-Ywarn-value-discard</arg>
84+
<arg>-Yrangepos</arg>
85+
</args>
86+
87+
</configuration>
88+
</plugin>
89+
90+
<plugin>
91+
<artifactId>maven-assembly-plugin</artifactId>
92+
<configuration>
93+
<archive>
94+
<manifest>
95+
<mainClass>net.ladstatt.javacv.SwingDemo</mainClass>
96+
</manifest>
97+
</archive>
98+
<descriptorRefs>
99+
<descriptorRef>jar-with-dependencies</descriptorRef>
100+
</descriptorRefs>
101+
</configuration>
102+
<executions>
103+
<execution>
104+
<phase>package</phase>
105+
<goals>
106+
<goal>single</goal>
107+
</goals>
108+
</execution>
109+
</executions>
110+
</plugin>
111+
</plugins>
112+
</build>
113+
114+
115+
</project>
116+
117+
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
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

Comments
 (0)