Last active
December 23, 2015 15:59
-
-
Save rladstaetter/6659193 to your computer and use it in GitHub Desktop.
An application to extract certain regions of an image stream which share the same color.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package net.ladstatt.apps | |
import javafx.scene._ | |
import org.opencv.core._ | |
import org.opencv.imgproc.Imgproc | |
import javafx.application.{Platform, Application} | |
import javafx.scene.control._ | |
import javafx.scene.image.ImageView | |
import javafx.scene.layout.BorderPane | |
import javafx.stage.Stage | |
import java.util.ResourceBundle | |
import javafx.fxml.{FXML, Initializable} | |
import java.net.URL | |
import javafx.beans.property.SimpleObjectProperty | |
import net.ladstatt.jfx._ | |
import org.controlsfx.control.{HsvSlider, RangeSlider} | |
object ColorExtractor { | |
def main(args: Array[String]): Unit = { | |
Application.launch(classOf[ColorExtractor], args: _*) | |
} | |
} | |
class ColorExtractor extends Application with JfxUtils with Initializable with OpenCVUtils { | |
val lowerBoundProperty = new SimpleObjectProperty[Scalar](new Scalar(0, 0, 0)) | |
def setLowerBound(lb: Scalar) = lowerBoundProperty.set(lb) | |
def getLowerBound() = lowerBoundProperty.get | |
val upperBoundProperty = new SimpleObjectProperty[Scalar](new Scalar(255, 255, 255)) | |
def setUpperBound(lb: Scalar) = upperBoundProperty.set(lb) | |
def getUpperBound() = upperBoundProperty.get | |
override def init(): Unit = loadNativeLibs // important to have this statement on the "right" thread | |
def colorSpace(conversionMethod: Int = Imgproc.COLOR_BGR2GRAY)(input: Mat): Mat = { | |
val colorTransformed = new Mat | |
Imgproc.cvtColor(input, colorTransformed, conversionMethod) | |
colorTransformed | |
} | |
def restrain(input: Mat): Mat = { | |
val dest = new Mat | |
val lb = getLowerBound() | |
val ub = getUpperBound() | |
Core.inRange(input, lb, ub, dest) | |
dest | |
} | |
def alphaBlend(src: Mat, alpha: Mat): Mat = { | |
val channels = new java.util.ArrayList[Mat]() | |
Core.split(src, channels) | |
channels.add(alpha) | |
val merged = new Mat | |
Core.merge(channels, merged) | |
merged | |
} | |
@FXML var textFieldLbHue: TextField = _ | |
@FXML var textFieldLbSaturation: TextField = _ | |
@FXML var textFieldLbValue: TextField = _ | |
@FXML var textFieldUbHue: TextField = _ | |
@FXML var textFieldUbSaturation: TextField = _ | |
@FXML var textFieldUbValue: TextField = _ | |
@FXML var hueSlider: HsvSlider = _ | |
@FXML var saturationSlider: HsvSlider = _ | |
@FXML var valueSlider: HsvSlider = _ | |
@FXML var viewPort: ImageView = _ | |
override def start(stage: Stage): Unit = { | |
stage.setTitle("Color Extractor") | |
val imageService = new WebcamService | |
imageService.setOnSucceeded( | |
mkEventHandler( | |
event => { | |
val imageAsMat = event.getSource.getValue.asInstanceOf[Mat] | |
val alphaChannel = restrain(colorSpace(Imgproc.COLOR_BGR2HSV)(imageAsMat)) | |
viewPort.imageProperty.set(toImage(alphaBlend(imageAsMat, alphaChannel))) | |
imageService.restart | |
} | |
)) | |
imageService.start | |
val scene = new Scene(mk[BorderPane](mkFxmlLoader("/colorextractor.fxml", this))) | |
stage.setScene(scene) | |
stage.show | |
} | |
def initialize(url: URL, resourceBundle: ResourceBundle): Unit = { | |
def initRangeSlider(pos: Int, slider: RangeSlider, lowerTextField: TextField, upperTextField: TextField): Unit = { | |
slider.lowValueProperty().addListener(mkChangeListener[Number]( | |
(obVal, oldVal, newVal) => { | |
val mutableBounds = getLowerBound.`val` | |
mutableBounds(pos) = newVal.doubleValue() | |
setLowerBound(new Scalar(mutableBounds)) | |
lowerTextField.setText("%.2f".format(newVal.doubleValue)) | |
} | |
)) | |
slider.highValueProperty().addListener(mkChangeListener[Number]( | |
(obVal, oldVal, newVal) => { | |
val mutableBounds = getUpperBound.`val` | |
mutableBounds(pos) = newVal.doubleValue() | |
setUpperBound(new Scalar(mutableBounds)) | |
upperTextField.setText("%.2f".format(newVal.doubleValue)) | |
} | |
)) | |
} | |
def setRangeSlider(slider: RangeSlider)(range: (Double, Double)) { | |
slider.setLowValue(range._1) | |
slider.setHighValue(range._2) | |
} | |
def setHueSlider = setRangeSlider(hueSlider) _ | |
def setSaturationSlider = setRangeSlider(saturationSlider) _ | |
def setValueSlider = setRangeSlider(valueSlider) _ | |
initRangeSlider(0, hueSlider, textFieldLbHue, textFieldUbHue) | |
initRangeSlider(1, saturationSlider, textFieldLbSaturation, textFieldUbSaturation) | |
initRangeSlider(2, valueSlider, textFieldLbValue, textFieldUbValue) | |
setHueSlider((0.0, 179.0)) | |
setSaturationSlider((0.0, 255.0)) | |
setValueSlider((0.0, 255.0)) | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment