implement basic UI

This commit is contained in:
Denis-Cosmin NUTIU 2024-03-21 22:36:26 +02:00
parent f66413710b
commit e221b6d06c
10 changed files with 185 additions and 34 deletions

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GoogleJavaFormatSettings">
<option name="enabled" value="false" />
</component>
</project>

View file

@ -5,6 +5,7 @@
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="corretto-21" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />

View file

@ -4,7 +4,7 @@
<component name="FrameworkDetectionExcludesConfiguration">
<file type="web" url="file://$PROJECT_DIR$" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="21" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="corretto-21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

View file

@ -25,7 +25,7 @@ tasks.withType(JavaCompile) {
application {
mainModule = 'com.nuculabs.dev.imagetagger.ui'
mainClass = 'com.nuculabs.dev.imagetagger.ui.MainApplication'
mainClass = 'com.nuculabs.dev.imagetagger.ui.MainPage'
}
kotlin {
jvmToolchain( 17 )

View file

@ -1,19 +0,0 @@
package com.nuculabs.dev.imagetagger.ui
import com.nuculabs.dev.imagetagger.tag_prediction.ImageTagsPrediction
import javafx.fxml.FXML
import javafx.scene.control.Label
import java.io.File
class HelloController {
@FXML
private lateinit var welcomeText: Label
@FXML
private fun onHelloButtonClick() {
val imageTagsPrediction = ImageTagsPrediction.getInstance()
val testTags = imageTagsPrediction.predictTags(File("/home/denis/Pictures/not_in_train/0a1a1e8bafbcdb00d34d87f35f0f4b9f.jpg").inputStream())
welcomeText.text = testTags.joinToString { it }
}
}

View file

@ -6,11 +6,11 @@ import javafx.fxml.FXMLLoader
import javafx.scene.Scene
import javafx.stage.Stage
class MainApplication : Application() {
class MainPage : Application() {
override fun start(stage: Stage) {
ImageTagsPrediction.getInstance()
val fxmlLoader = FXMLLoader(MainApplication::class.java.getResource("main-window-view.fxml"))
val fxmlLoader = FXMLLoader(MainPage::class.java.getResource("main-window-view.fxml"))
val scene = Scene(fxmlLoader.load(), 640.0, 760.0)
stage.title = "Image Tagger"
stage.scene = scene
@ -21,5 +21,5 @@ class MainApplication : Application() {
}
fun main() {
Application.launch(MainApplication::class.java)
Application.launch(MainPage::class.java)
}

View file

@ -0,0 +1,62 @@
package com.nuculabs.dev.imagetagger.ui
import com.nuculabs.dev.imagetagger.tag_prediction.ImageTagsPrediction
import com.nuculabs.dev.imagetagger.ui.controls.ImageTagsEntry
import javafx.application.Platform
import javafx.fxml.FXML
import javafx.scene.control.Label
import javafx.scene.control.Separator
import javafx.scene.layout.VBox
import javafx.stage.FileChooser
import java.io.File
import java.util.logging.Logger
import javax.imageio.ImageIO
class MainPageController {
private val logger: Logger = Logger.getLogger("InfoLogging")
@FXML
private lateinit var verticalBox: VBox
@FXML
private lateinit var statusLabel: Label
/**
* Prompts the user to select files then predicts tags for the selected image files.
*/
@FXML
private fun onTagImagesButtonClick() {
val imageTagsPrediction = ImageTagsPrediction.getInstance()
val fileChooser = FileChooser()
fileChooser.title = "Choose images"
val filePaths = fileChooser.showOpenMultipleDialog(null) ?: return
statusLabel.isVisible = true
// Create a new thread to predict the images.
val thread = Thread {
try {
for (filePath in filePaths) {
// Get predictions for the image.
val imageFile = ImageIO.read(File(filePath.absolutePath))
val tags: List<String> = imageTagsPrediction.predictTags(imageFile)
Platform.runLater {
// Add image and prediction to the view.
verticalBox.children.add(
Label("${filePath.name} - $tags")
)
verticalBox.children.add(Separator())
}
}
Platform.runLater {
statusLabel.setVisible(false)
}
} catch (e: Exception) {
logger.warning("Error while predicting images $e")
}
}
thread.start()
}
}

View file

@ -0,0 +1,67 @@
package com.nuculabs.dev.imagetagger.ui.controls
import javafx.fxml.FXML
import javafx.fxml.FXMLLoader
import javafx.scene.control.TextArea
import javafx.scene.image.Image
import javafx.scene.image.ImageView
import javafx.scene.layout.HBox
import java.io.IOException
/**
* This class is used to create a custom control for the image prediction entry.
*/
class ImageTagsEntry(imagePath: String, predictions: List<String>) : HBox() {
/**
* The image view for the image prediction entry.
*/
@FXML
private lateinit var imageView: ImageView
/**
* The text area for the image prediction entry.
*/
@FXML
private lateinit var predictedImageTags: TextArea
/**
* Constructor for the image prediction entry.
*
* @param imagePath The image path.
* @param predictions The prediction list.
*/
init {
val fxmlLoader = FXMLLoader(ImageTagsEntry::class.java.getResource("/controls/image-tags-entry.fxml"))
fxmlLoader.setRoot(this)
fxmlLoader.setController(this)
try {
fxmlLoader.load<Any>()
} catch (exception: IOException) {
throw RuntimeException(exception)
}
setImage(imagePath)
setText(predictions)
}
/**
* Getter for the image view.
*
* @param predictions The prediction list.
*/
fun setText(predictions: List<String>) {
predictedImageTags.text = predictions.joinToString { it }
}
/**
* Setter for setting the image.
*/
fun setImage(imagePath: String?) {
imageView.image = Image(imagePath)
imageView.resize(244.0, 244.0)
imageView.fitHeight = 244.0
imageView.fitWidth = 244.0
imageView.isSmooth = true
imageView.isCache = true
}
}

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.image.ImageView?>
<fx:root type="javafx.scene.layout.HBox" xmlns:fx="http://javafx.com/fxml">
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0"/>
</padding>
<HBox>
<ImageView fx:id="imageView" />
<VBox>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0"/>
</padding>
<Label text="Predicted tags:"/>
<TextArea fx:id="predictedImageTags" editable="false" wrapText="true" prefColumnCount="23"/>
</VBox>
</HBox>
</fx:root>

View file

@ -1,16 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.control.Button?>
<VBox alignment="CENTER" spacing="20.0" xmlns:fx="http://javafx.com/fxml"
fx:controller="com.nuculabs.dev.imagetagger.ui.HelloController">
<BorderPane prefHeight="537.0" prefWidth="725.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/17.0.2-ea" fx:controller="com.nuculabs.dev.imagetagger.ui.MainPageController">
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0"/>
<Insets bottom="20.0" left="30.0" right="30.0" top="30.0" />
</padding>
<center>
<ScrollPane>
<VBox fx:id="verticalBox">
</VBox>
</ScrollPane>
</center>
<Label fx:id="welcomeText"/>
<Button text="Hello!" onAction="#onHelloButtonClick"/>
</VBox>
<bottom>
<HBox alignment="CENTER_LEFT">
<padding>
<Insets bottom="5" left="5" right="5" top="10" />
</padding>
<Button onAction="#onTagImagesButtonClick" text="Tag Images" />
<Separator orientation="VERTICAL" style="-fx-padding: 10px" />
<Label fx:id="statusLabel" visible="false" text="Predicting... please wait" />
</HBox>
</bottom>
</BorderPane>