Compare commits

...

16 Commits

Author SHA1 Message Date
6df1a451ec added face detection 2023-12-07 10:49:42 +01:00
791f6b7b88 task 9 2023-12-07 10:49:42 +01:00
979807f399 task 8.4 2023-12-07 10:49:42 +01:00
0657c28d7d task 8.3 2023-12-07 10:49:42 +01:00
ee6999b095 task 8.2 2023-12-07 10:49:42 +01:00
f8db769ec3 fixed inverted x and y axes 2023-12-07 10:49:42 +01:00
cdd9a08635 task 8.1 2023-12-07 10:49:42 +01:00
0943bfa193 task 7 2023-12-07 10:49:42 +01:00
0a7a647126 task 6 2023-12-07 10:49:42 +01:00
ddd8952e9a task 5 2023-12-07 10:49:42 +01:00
54fa312113 task 4.2 2023-12-07 10:49:41 +01:00
ddddbfe558 task 4.1 2023-12-07 10:49:41 +01:00
9454948799 task 3 2023-12-07 10:49:41 +01:00
16e6e51472 task 2 2023-12-07 10:49:41 +01:00
e33f77b46e task 1 2023-12-07 10:49:41 +01:00
309088e5d2 part 1 task 0 2023-12-07 10:49:40 +01:00
20 changed files with 657 additions and 0 deletions

18
Lab11.iml Normal file
View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="scala-sdk-2.13.12" level="project" />
<orderEntry type="library" name="bridj-0.7.0" level="project" />
<orderEntry type="library" name="slf4j-api-1.7.2" level="project" />
<orderEntry type="library" name="webcam-capture-0.3.12" level="project" />
<orderEntry type="library" name="bytedeco.javacv" level="project" />
<orderEntry type="library" name="bytedeco.javacv.platform" level="project" />
</component>
</module>

BIN
libs/bridj-0.7.0.jar Normal file

Binary file not shown.

BIN
libs/slf4j-api-1.7.2.jar Normal file

Binary file not shown.

Binary file not shown.

BIN
res/Dead_tree.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

BIN
res/collins_eileen.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 KiB

BIN
res/grace_hopper.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

BIN
res/imageProcessing.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
res/mask.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
res/mask640x480.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
res/moire1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 KiB

BIN
res/moire2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
res/rice.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

9
src/TestArray.scala Normal file
View File

@@ -0,0 +1,9 @@
object TestArray extends App {
def arrayAvg(arr: Array[Double]): Double = {
if (arr.isEmpty) return 0
return arr.sum / arr.length
}
val arr: Array[Double] = Array.range(1, 1001).map(i => i.toDouble)
println(arrayAvg(arr))
}

View File

@@ -0,0 +1,189 @@
package imagefilters
import java.awt.Color
/**
* This class implements the various image filters
*/
object ImageFilters {
// Default factors (reference values)
/*val SEPIA_FACTORS: Array[Array[Double]] = Array(
Array( 0.393, 0.769, 0.189),
Array( 0.349, 0.686, 0.168),
Array( 0.272, 0.534, 0.131)
)*/
// Adapted factors (matches the example in the instructions)
val SEPIA_FACTORS: Array[Array[Double]] = Array(
Array( 0.883, 0.004, 0.003),
Array(-0.058, 0.791,-0.097),
Array( 0.034,-0.244, 0.583)
)
def filter(src: Array[Array[Int]], func: (Int, Int, Int, Int, Int) => Int): Array[Array[Int]] = {
val width: Int = src.length
val height: Int = if (width == 0) 0 else src(0).length
val dst: Array[Array[Int]] = Array.ofDim(width, height)
for (x: Int <- 0 until width) {
for (y: Int <- 0 until height) {
dst(x)(y) = func(src(x)(y), x, y, width, height)
}
}
return dst
}
def filter(src: Array[Array[Int]], func: (Int) => Int): Array[Array[Int]] = filter(src, (value, x, y, width, height) => func(value))
def colorFilter(src: Array[Array[Color]], func: (Color, Int, Int, Int, Int) => Color): Array[Array[Color]] = {
val width: Int = src.length
val height: Int = if (width == 0) 0 else src(0).length
val dst: Array[Array[Color]] = Array.ofDim(width, height)
for (x: Int <- 0 until width) {
for (y: Int <- 0 until height) {
dst(x)(y) = func(src(x)(y), x, y, width, height)
}
}
return dst
}
def colorFilter(src: Array[Array[Color]], func: (Color) => Color): Array[Array[Color]] = colorFilter(src, (value, x, y, width, height) => func(value))
def duplicate(a: Array[Array[Int]]): Array[Array[Int]] = filter(a, (value) => value)
def threshold(a: Array[Array[Int]], thresh: Int): Array[Array[Int]] = filter(a, (value) => if (value > thresh) 255 else 0)
def mean(a: Array[Array[Int]]): Array[Array[Int]] = filter(a, (value, x, y, width, height) => {
if (x == 0 || x == width - 1 || y == 0 || y == height - 1) value
else {
var avg: Double = 0
for (dx: Int <- -1 to 1) {
for (dy: Int <- -1 to 1) {
avg += a(x+dx)(y+dy)
}
}
(avg/9.0).toInt
}
})
def mean(a: Array[Array[Int]], radius: Int): Array[Array[Int]] = {
if (radius < 0) throw new IllegalArgumentException("radius must be >= 0")
val diameter: Int = 2 * radius + 1
filter(a, (value, x, y, width, height) => {
if (x <= radius - 1 || x >= width - radius || y <= radius - 1 || y >= height - radius) value
else {
var avg: Double = 0
for (dx: Int <- -radius to radius) {
for (dy: Int <- -radius to radius) {
avg += a(x+dx)(y+dy)
}
}
(avg/(diameter * diameter)).toInt
}
})
}
def edges(a: Array[Array[Int]]): Array[Array[Int]] = filter(a, (value, x, y, width, height) => {
if (x == 0 || x == width - 1 || y == 0 || y == height - 1) value
else {
val dx: Int = a(x+1)(y) - a(x-1)(y)
val dy: Int = a(x)(y+1) - a(x)(y-1)
Math.sqrt(dx*dx + dy*dy).toInt
}
})
def sobel(a: Array[Array[Int]], intensityFactor: Double): Array[Array[Int]] = filter(a, (value, x, y, width, height) => {
if (x == 0 || x == width - 1 || y == 0 || y == height - 1) value
else {
val dx: Int = a(x+1)(y-1) + 2*a(x+1)(y) + a(x+1)(y+1) - a(x-1)(y-1) - 2*a(x-1)(y) - a(x-1)(y+1)
val dy: Int = a(x-1)(y+1) + 2*a(x)(y+1) + a(x+1)(y+1) - a(x-1)(y-1) - 2*a(x)(y-1) - a(x+1)(y-1)
(Math.sqrt(dx*dx + dy*dy)*intensityFactor).toInt
}
})
def noise(a: Array[Array[Int]], intensity: Double): Array[Array[Int]] = filter(a, (value) => {
Math.max(0, Math.min(255, value + (Math.random()*2-1)*intensity)).toInt
})
def noise(a: Array[Array[Color]], intensity: Double): Array[Array[Color]] = colorFilter(a, (col) => {
val r: Double = col.getRed + (Math.random()*2-1)*intensity
val g: Double = col.getGreen + (Math.random()*2-1)*intensity
val b: Double = col.getBlue + (Math.random()*2-1)*intensity
new Color(
Math.max(0, Math.min(255, r)).toInt,
Math.max(0, Math.min(255, g)).toInt,
Math.max(0, Math.min(255, b)).toInt
)
})
def mask(a: Array[Array[Color]], maskImg: Array[Array[Int]]): Array[Array[Color]] = {
val maskWidth: Int = maskImg.length
val maskHeight: Int = if (maskWidth == 0) 0 else maskImg(0).length
colorFilter(a, (col, x, y, width, height) => {
if (x >= maskWidth || y >= maskHeight) col
else {
val factor: Double = maskImg(x)(y)/255.0
new Color(
(col.getRed * factor).toInt,
(col.getGreen * factor).toInt,
(col.getBlue * factor).toInt
)
}
})
}
def getAvgInPixel(a: Array[Array[Color]], pixelSize: Int, px: Int, py: Int): Color = {
val width: Int = a.length
val height: Int = if (width == 0) 0 else a(0).length
var r: Double = 0
var g: Double = 0
var b: Double = 0
var cnt: Int = 0
for (x: Int <- px*pixelSize until (px+1)*pixelSize) {
for (y: Int <- py*pixelSize until (py+1)*pixelSize) {
if (x < width && y < height) {
cnt += 1
r += a(x)(y).getRed
g += a(x)(y).getGreen
b += a(x)(y).getBlue
}
}
}
return new Color((r/cnt).toInt, (g/cnt).toInt, (b/cnt).toInt)
}
def pixelize(a: Array[Array[Color]], pixelSize: Int): Array[Array[Color]] = {
val width: Int = a.length
val height: Int = if (width == 0) 0 else a(0).length
val hPixels: Int = Math.ceil(width.toDouble/pixelSize).toInt
val vPixels: Int = Math.ceil(height.toDouble/pixelSize).toInt
val pixels: Array[Array[Color]] = Array.ofDim[Color](hPixels, vPixels)
for (x: Int <- 0 until hPixels) {
for (y: Int <- 0 until vPixels) {
pixels(x)(y) = getAvgInPixel(a, pixelSize, x, y)
}
}
colorFilter(a, (col, x, y, w, h) => pixels(x/pixelSize)(y/pixelSize))
}
def pixelize(a: Array[Array[Color]], pixelSize: Int, x1: Int, y1: Int, x2: Int, y2: Int): Array[Array[Color]] = {
val pixelated: Array[Array[Color]] = pixelize(a, pixelSize)
colorFilter(a, (col, x, y, w, h) => {
if (x1 <= x && x <= x2 && y1 <= y && y <= y2) {
pixelated(x)(y)
}
else col
})
}
def sepia(a: Array[Array[Color]]): Array[Array[Color]] = colorFilter(a, (col) => {
val r: Double = Math.max(0, Math.min(255, col.getRed * SEPIA_FACTORS(0)(0) +
col.getGreen * SEPIA_FACTORS(0)(1) +
col.getBlue * SEPIA_FACTORS(0)(2)))
val g: Double = Math.max(0, Math.min(255, col.getRed * SEPIA_FACTORS(1)(0) +
col.getGreen * SEPIA_FACTORS(1)(1) +
col.getBlue * SEPIA_FACTORS(1)(2)))
val b: Double = Math.max(0, Math.min(255, col.getRed * SEPIA_FACTORS(2)(0) +
col.getGreen * SEPIA_FACTORS(2)(1) +
col.getBlue * SEPIA_FACTORS(2)(2)))
new Color(r.toInt, g.toInt, b.toInt)
})
}

View File

@@ -0,0 +1,61 @@
package imagefilters
import isc.graphics.ImageGraphics
object ImageProcessingApp extends App {
/*val imageFile = "./res/collins_eileen.png"
val org = new ImageGraphics(imageFile, "Original", -500, -250)
val dest = new ImageGraphics(imageFile, "Duplicate", 0, -250)
val thresh = new ImageGraphics(imageFile, "Threshold", -500, 250)
// Simple copy and display
val newPixels = ImageFilters.duplicate(org.getPixelsBW())
dest.setPixelsBW(newPixels)
thresh.setPixelsBW(ImageFilters.threshold(newPixels, 128))
val mean = new ImageGraphics("./res/imageProcessing.jpg", "Mean", 0, 250)
mean.setPixelsBW(ImageFilters.mean(mean.getPixelsBW()))
val mean2 = new ImageGraphics("./res/imageProcessing.jpg", "Mean 2", 250, 250)
mean2.setPixelsBW(ImageFilters.mean(mean2.getPixelsBW(), 4))
val edges = new ImageGraphics("./res/rice.jpg", "Edges", 500, 250)
edges.setPixelsBW(ImageFilters.edges(edges.getPixelsBW()))*/
/*val imageFile: String = "./res/grace_hopper.jpg"
val org = new ImageGraphics(imageFile, "Original", -768, -512)
val bw = new ImageGraphics(imageFile, "Black & White", -256, -512)
val threshold = new ImageGraphics(imageFile, "Threshold", 256, -512)
val blur = new ImageGraphics(imageFile, "Blurred", -768, 0)
val edges = new ImageGraphics(imageFile, "Edge detection", -256, 0)
val sobel = new ImageGraphics(imageFile, "Sobel", 256, 0)
val noise = new ImageGraphics(imageFile, "Noise", -768, 512)
bw.setPixelsBW(ImageFilters.duplicate(org.getPixelsBW()))
threshold.setPixelsBW(ImageFilters.threshold(org.getPixelsBW(), 128))
blur.setPixelsBW(ImageFilters.mean(org.getPixelsBW(), 3))
edges.setPixelsBW(ImageFilters.edges(org.getPixelsBW()))
sobel.setPixelsBW(ImageFilters.sobel(org.getPixelsBW(), 0.3))
noise.setPixelsBW(ImageFilters.noise(org.getPixelsBW(), 30))*/
/*val imageFile: String = "./res/collins_eileen.png"
val maskFile: String = "./res/mask.png"
val org = new ImageGraphics(imageFile, "Original", -768, -512)
val mask = new ImageGraphics(maskFile, "Mask", -256, -512)
val masked = new ImageGraphics(imageFile, "Masked", 256, -512)
masked.setPixelsColor(ImageFilters.mask(org.getPixelsColor(), mask.getPixelsBW()))*/
/*val imageFile: String = "./res/grace_hopper.jpg"
val org = new ImageGraphics(imageFile, "Original", -768, -512)
val pixelated = new ImageGraphics(imageFile, "Pixelated", -256, -512)
pixelated.setPixelsColor(ImageFilters.pixelize(org.getPixelsColor(), 30, 130, 120, 400, 230))*/
val imageFile: String = "./res/collins_eileen.png"
val org = new ImageGraphics(imageFile, "Original", -768, -512)
val sepia = new ImageGraphics(imageFile, "Sepia", -256, -512)
val noise = new ImageGraphics(imageFile, "Noise", 256, -512)
sepia.setPixelsColor(ImageFilters.sepia(org.getPixelsColor()))
noise.setPixelsColor(ImageFilters.noise(org.getPixelsColor(), 50))
}

View File

@@ -0,0 +1,241 @@
package isc.graphics
import java.awt._
import java.awt.image.BufferedImage
import java.io.{File, FileInputStream}
import javax.imageio.ImageIO
import javax.swing.{JFrame, JPanel}
/**
* [ImageGraphics] helpers functions in companion object.
*/
object ImageGraphics {
/**
* Converts a color array to a black-or-white array
*
* @param c The color array
* @return The array converted to BW
*/
def convertToGray(c: Array[Array[Color]]): Array[Array[Color]] = {
val w = c.length
val h = c(0).length
val values = Array.ofDim[Color](w, h)
// FIXME this is slow
for (i <- 0 until w) {
for (j <- 0 until h) {
val col = c(i)(j)
val intColor = (0.3 * col.getRed + 0.59 * col.getGreen + 0.11 * col.getBlue).toInt
values(i)(j) = new Color(intColor, intColor, intColor)
}
}
values
}
def convertToGrayInt(c: Array[Array[Color]]): Array[Array[Int]] = {
val w = c.length
val h = c(0).length
val values = Array.ofDim[Int](w, h)
for (i <- 0 until w) {
for (j <- 0 until h) {
val col = c(i)(j)
val intColor = (0.3 * col.getRed + 0.59 * col.getGreen + 0.11 * col.getBlue).toInt
values(i)(j) = intColor
}
}
values
}
def main(args: Array[String]): Unit = {
val imageUsed = "res/grace_hopper.jpg"
val org = new ImageGraphics(imageUsed, "Original", 0, 0)
}
}
/**
* This class was made to deal with images as multidimensional arrays.
* Mainly used in the <code>ImageProcessing</code> lab. It expects the images to reside in the <code>src</code> directory
*
* @author Pierre-André Mudry
* @version 1.0
* @constructor
*
* @param filePath the path of the file, relative to the project. For instance, "./res/grace_hopper.jpg"
* @param windowTitle the title
* @param xPositionOffset the x offset
* @param yPositionOffset the y offet
*/
class ImageGraphics(val filePath: String, val windowTitle: String,
val xPositionOffset: Int, val yPositionOffset: Int) extends JFrame {
private var imgBuffer: BufferedImage = null
private var w = 0
private var h = 0
class ImgPanel extends JPanel {
override def paint(g: Graphics): Unit = {
super.paint(g)
g.drawImage(imgBuffer, 0, 0, null)
g.dispose()
}
}
val imgPanel = new ImgPanel()
try { // Fill the frame content with the image
try {
imgBuffer = ImageIO.read(new FileInputStream(new File(filePath)))
w = imgBuffer.getWidth
h = imgBuffer.getHeight
} catch {
case e: Exception =>
println("Could not load directly, using classpath.")
}
// If the first technique failed, try using resource instead
if (imgBuffer == null) {
try {
imgBuffer = ImageIO.read(classOf[ImageGraphics].getResource(filePath))
w = imgBuffer.getWidth
h = imgBuffer.getHeight
} catch {
case e: Exception =>
System.err.println("Could not find image " + filePath + ", exiting !")
e.printStackTrace()
System.exit(-1)
}
}
this.setResizable(false)
this.setTitle(windowTitle)
this.setLayout(new BorderLayout())
this.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE)
imgPanel.setPreferredSize(new Dimension(imgBuffer.getWidth, imgBuffer.getHeight))
this.add(imgPanel, BorderLayout.CENTER)
this.pack()
// Get the size of the screen
val dim = Toolkit.getDefaultToolkit.getScreenSize
// Determine the new location of the window
val lw = this.getSize.width
val lh = this.getSize.height
val x = (dim.width - lw) / 2 + xPositionOffset
val y = (dim.height - lh) / 2 + yPositionOffset
// Move the window
this.setLocation(x, y)
this.setVisible(true)
} catch {
case e: Exception =>
e.printStackTrace()
}
/**
* Sets a grayscale pixel, does not sets values for invalid pixels
* outside the screen. Does not repaint the screen either because it
* is slow.
*
* @param x
* @param y
* @param intensity
*/
def setPixelBW(x: Int, y: Int, intensity: Int): Unit = {
if (!((x < 0) || (y < 0) || (x >= w) || (y >= h)))
imgBuffer.setRGB(x, y, intensity << 16 | intensity << 8 | intensity)
}
/**
* Sets an array of grayscale pixels (from 0 to 255) and displays them
*
* @param pixels
*/
def setPixelsBW(pixels: Array[Array[Int]]): Unit = {
try {
if (pixels(0).length != h || pixels.length != w) throw new Exception("Invalid size of the pixel array !")
for (i <- 0 until w) {
for (j <- 0 until h) {
val c = pixels(i)(j) << 16 | pixels(i)(j) << 8 | pixels(i)(j)
imgBuffer.setRGB(i, j, c)
}
}
this.repaint()
} catch {
case e: Exception =>
e.printStackTrace()
}
}
/**
* Sets an array of pixels of Color and displays them
*
* @param pixels
*/
def setPixelsColor(pixels: Array[Array[Color]]): Unit = {
try {
if (pixels(0).length != h || pixels.length != w) throw new Exception("Invalid size of the pixel array !")
for (i <- 0 until w) {
for (j <- 0 until h) {
imgBuffer.setRGB(i, j, pixels(i)(j).getRGB)
}
}
this.repaint()
} catch {
case e: Exception =>
e.printStackTrace()
}
}
/**
* Gets a single pixel from the background image and returns its
* grayscale value
*
* @param x the x coordinate
* @param y the y coordinate
* @return the pixel
*/
def getPixelBW(x: Int, y: Int): Int =
if ((x < 0) || (y < 0) || (x >= w) || (y >= h)) {
0
}
else {
// Inside the image. Make the gray conversion and return the value
val c = new Color(imgBuffer.getRGB(x, y))
(0.3 * c.getRed + 0.59 * c.getGreen + 0.11 * c.getBlue).toInt
}
/**
* Gets the array of the pixels (which have been converted to grayscale
* if required)
*
* @return The arrays of gray pixels
*/
def getPixelsBW(): Array[Array[Int]] = {
val values = Array.ofDim[Int](w, h)
for (i <- 0 until w) {
for (j <- 0 until h) {
val c = new Color(imgBuffer.getRGB(i, j))
values(i)(j) = (0.3 * c.getRed + 0.59 * c.getGreen + 0.11 * c.getBlue).toInt
}
}
values
}
/**
* Gets the array of the pixels as Colors (see #Color)
*
* @return The arrays of pixels
*/
def getPixelsColor(): Array[Array[Color]] = {
val values = Array.ofDim[Color](w, h)
for (i <- 0 until w) {
for (j <- 0 until h) {
values(i)(j) = new Color(imgBuffer.getRGB(i, j))
}
}
values
}
}

View File

@@ -0,0 +1,36 @@
package livefilter
import org.bytedeco.javacpp.Loader
import org.bytedeco.javacpp.indexer.UByteRawIndexer
import org.bytedeco.opencv.global.opencv_core.CV_8U
import org.bytedeco.opencv.opencv_core.{Mat, Rect, RectVector}
import org.bytedeco.opencv.opencv_objdetect.CascadeClassifier
import java.io.File
import java.net.URL
object FaceDetection {
val url: URL = new URL("https://raw.github.com/opencv/opencv/master/data/haarcascades/haarcascade_frontalface_alt.xml")
val file: File = Loader.cacheResource(url)
val classifierName: String = file.getAbsolutePath
val cascade: CascadeClassifier = new CascadeClassifier(classifierName)
def detectFaces(src: Array[Array[Int]]): Array[Rect] = {
val grayFrame: Mat = new Mat()
val width: Int = src.length
val height: Int = if (width == 0) 0 else src(0).length
grayFrame.create(height, width, CV_8U)
val idx: UByteRawIndexer = grayFrame.createIndexer()
for (x: Int <- 0 until width) {
for (y: Int <- 0 until height) {
idx.put(y, x, src(x)(y))
}
}
val faces: RectVector = new RectVector()
cascade.detectMultiScale(grayFrame, faces)
return faces.get()
}
}

View File

@@ -0,0 +1,103 @@
package livefilter
import com.github.sarxos.webcam.WebcamPanel.DrawMode
import com.github.sarxos.webcam.{Webcam, WebcamImageTransformer, WebcamPanel, WebcamResolution}
import imagefilters.ImageFilters
import org.bytedeco.opencv.opencv_core.{Rect, RectVector}
import java.awt.image.BufferedImage
import java.awt.{Color, Dimension}
import java.io.{File, FileInputStream}
import javax.imageio.ImageIO
import javax.swing.JFrame
object LiveFilter {
def main(args: Array[String]): Unit = {
new LiveFilter()
}
}
/**
* A live filter class using VGA resolution
*/
class LiveFilter extends WebcamImageTransformer {
val size: Dimension = WebcamResolution.VGA.getSize
val MASK: String = "./res/mask640x480.png"
val videoMask: Array[Array[Int]] = toBW(ImageIO.read(new FileInputStream(new File(MASK))))
// Gets default webcam and sets image transformer to this (transformer will modify
// image after it's been received from webcam, in this case it will rotate it)
val webcam: Webcam = Webcam.getDefault
//val webcam: Webcam = Webcam.getWebcamByName("/dev/video2")
webcam.setViewSize(size)
println(size)
webcam.setImageTransformer(this)
webcam.open
// Create a window
val window = new JFrame("Test filter")
// Creates a panel to put the webcam image in it
val panel = new WebcamPanel(webcam)
panel.setFPSDisplayed(true)
panel.setDrawMode(DrawMode.FIT)
// Add panel to window
window.add(panel)
window.pack()
window.setVisible(true)
window.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE)
def toBW(img: BufferedImage): Array[Array[Int]] = {
val o = Array.ofDim[Int](img.getWidth(), img.getHeight())
for (x <- o.indices) {
for (y <- o(0).indices) {
val c = new Color(img.getRGB(x, y))
o(x)(y) = (0.3 * c.getRed + 0.59 * c.getGreen + 0.11 * c.getBlue).toInt
}
}
o
}
def toArray(image: BufferedImage): Array[Array[Color]] = {
val out = Array.ofDim[Color](image.getWidth, image.getHeight)
for (x <- out.indices; y <- out(0).indices) {
out(x)(y) = new Color(image.getRGB(x, y))
}
out
}
private def updateImage(in: Array[Array[Color]], out: BufferedImage): Unit = {
for (x <- in.indices; y <- in(0).indices) {
out.setRGB(x, y, in(x)(y).getRGB)
}
}
/**
* Applies the various filters to the buffer
*
* @param image The input image
* @return The filtered image
*/
override def transform(image: BufferedImage): BufferedImage = {
val img: Array[Array[Color]] = toArray(image)
val bw: Array[Array[Int]] = toBW(image)
val faces: Array[Rect] = FaceDetection.detectFaces(bw)
var filtered: Array[Array[Color]] = img
for (rect: Rect <- faces) {
filtered = ImageFilters.pixelize(filtered, 10, rect.x, rect.y, rect.x+rect.width, rect.y+rect.height)
}
//val filtered: Array[Array[Color]] = ImageFilters.mask(ImageFilters.sepia(ImageFilters.noise(img, 10)), videoMask)
updateImage(filtered, image)
return image
}
}