task 1
@ -8,5 +8,8 @@
|
||||
<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" />
|
||||
</component>
|
||||
</module>
|
BIN
libs/bridj-0.7.0.jar
Normal file
BIN
libs/slf4j-api-1.7.2.jar
Normal file
BIN
libs/webcam-capture-0.3.12.jar
Normal file
BIN
res/Dead_tree.png
Normal file
After Width: | Height: | Size: 94 KiB |
BIN
res/collins_eileen.png
Normal file
After Width: | Height: | Size: 285 KiB |
BIN
res/grace_hopper.jpg
Normal file
After Width: | Height: | Size: 60 KiB |
BIN
res/imageProcessing.jpg
Normal file
After Width: | Height: | Size: 140 KiB |
BIN
res/imageProcessing_empty.jpg
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
res/mask.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
res/mask640x480.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
res/moire1.png
Normal file
After Width: | Height: | Size: 279 KiB |
BIN
res/moire2.jpg
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
res/rice.jpg
Normal file
After Width: | Height: | Size: 14 KiB |
13
src/imagefilters/ImageFilters.scala
Normal file
@ -0,0 +1,13 @@
|
||||
package imagefilters
|
||||
|
||||
/**
|
||||
* This class implements the various image filters
|
||||
*/
|
||||
object ImageFilters {
|
||||
|
||||
def duplicate(a: Array[Array[Int]]): Array[Array[Int]] = {
|
||||
|
||||
/* TODO: Write your code hereunder */
|
||||
return Array.empty
|
||||
}
|
||||
}
|
14
src/imagefilters/ImageProcessingApp.scala
Normal file
@ -0,0 +1,14 @@
|
||||
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)
|
||||
|
||||
// Simple copy and display
|
||||
val newPixels = ImageFilters.duplicate(org.getPixelsBW())
|
||||
dest.setPixelsBW(newPixels)
|
||||
}
|
241
src/isc/graphics/ImageGraphics.scala
Normal 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
|
||||
}
|
||||
}
|
95
src/livefilter/LiveFilter.scala
Normal file
@ -0,0 +1,95 @@
|
||||
package livefilter
|
||||
|
||||
import com.github.sarxos.webcam.WebcamPanel.DrawMode
|
||||
import com.github.sarxos.webcam.{Webcam, WebcamImageTransformer, WebcamPanel, WebcamResolution}
|
||||
|
||||
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)
|
||||
|
||||
// TODO Complete here by changing the assignment with your filters
|
||||
val filtered: Array[Array[Color]] = img
|
||||
|
||||
updateImage(filtered, image)
|
||||
return image
|
||||
}
|
||||
}
|