我看到了http://opencv-java-tutorials.readthedocs.io/en/latest/05-fourier-transform.html,我想在Spring Framework中做到这一点。它似乎运作良好。但是控制器的数量是2.当我点击按钮时,出现新的控制器。如何修改以获得相同的控制器?
App.java
package com.hoex.fourier;
import org.opencv.core.Core;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
/**
* Hello world!
*
*/
@SpringBootApplication
public class App extends Application {
private static String[] args;
public static void main( String[] args ) {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
App.args = args;
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
try {
ApplicationContext context = SpringApplication.run(App.class, args);
// Create a Scene
FourierController fourierController = context.getBean(FourierController.class);
System.out.println("Bean FourierController--------------");
System.out.println(fourierController);
System.out.println("Bean FourierController--------------");
fourierController.setRoot((BorderPane)FXMLLoader.load(getClass().getResource(FourierController.VIEW)));
System.out.println("App primaryStage -----------------");
System.out.println(primaryStage);
System.out.println("App primaryStage -----------------");
fourierController.setStage(primaryStage);
System.out.println("App set primaryStage -----------------");
System.out.println(fourierController.getStage());
System.out.println("App set primaryStage -----------------");
Scene scene = new Scene((Parent)fourierController.getRoot());
// Set the scene on the primary stage
primaryStage.setScene(scene);
// Any other shenanigans on the primary stage
primaryStage.show();
System.out.println("App Root ---------------------");
System.out.println(primaryStage.getScene().getRoot());
System.out.println(fourierController.getRoot());
System.out.println("App Root ---------------------");
} catch(Exception e) {
e.printStackTrace();
}
}
}
AppConfig.java
package com.hoex.fourier;
import java.io.IOException;
import java.io.InputStream;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javafx.fxml.FXMLLoader;
@Configuration
public class AppConfig {
@Bean
public FourierController fourierController() throws IOException {
return loadController(FourierController.VIEW);
}
private <T> T loadController(String url) throws IOException {
try (InputStream fxmlStream = getClass().getResourceAsStream(url)) {
FXMLLoader loader = new FXMLLoader();
loader.load(fxmlStream);
return loader.getController();
}
}
}
FourierController.java
package com.hoex.fourier;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.imgcodecs.Imgcodecs;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
public class FourierController {
public static final String VIEW = "fxml/Fourier.fxml";
@FXML
private Node root;
// images to show in the view
@FXML
private ImageView originalImage;
@FXML
private ImageView transformedImage;
@FXML
private ImageView antitransformedImage;
// a FXML button for performing the transformation
@FXML
private Button transformButton;
// a FXML button for performing the antitransformation
@FXML
private Button antitransformButton;
// the main stage
private Stage stage;
// the JavaFX file chooser
// private FileChooser fileChooser;
private FileChooser fileChooser = new FileChooser();
// support variables
// private Mat image;
private Mat image = new Mat();
// private List<Mat> planes;
private List<Mat> planes = new ArrayList<>();
// the final complex image
// private Mat complexImage;
private Mat complexImage = new Mat();
public Node getRoot() {
return root;
}
public void setRoot(Node root) {
this.root = root;
}
/**
* Init the needed variables
*/
@PostConstruct
protected void init() {
System.out.println("Bean init -------------------------");
System.out.println(this);
System.out.println("Bean init -------------------------");
fileChooser = new FileChooser();
image = new Mat();
planes = new ArrayList<>();
complexImage = new Mat();
}
/**
* Load an image from disk
*/
@FXML
protected void loadImage()
{
System.out.println("loadImage -------------------------");
System.out.println(this);
System.out.println("loadImage -------------------------");
System.out.println("loadImage stage -------------------------");
System.out.println(stage);
System.out.println("loadImage stage -------------------------");
// show the open dialog window
File file = fileChooser.showOpenDialog(stage);
if (file != null)
{
// read the image in gray scale
image = Imgcodecs.imread(file.getAbsolutePath(), Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE);
// show the image
originalImage.setImage(mat2Image(image));
// set a fixed width
originalImage.setFitWidth(250);
// preserve image ratio
originalImage.setPreserveRatio(true);
// update the UI
transformButton.setDisable(false);
// empty the image planes and the image views if it is not the first
// loaded image
if (!planes.isEmpty())
{
planes.clear();
transformedImage.setImage(null);
antitransformedImage.setImage(null);
}
}
}
/**
* The action triggered by pushing the button for apply the dft to the
* loaded image
*/
@FXML
protected void transformImage()
{
System.out.println("transformImage -------------------------");
System.out.println(this);
System.out.println(this);
System.out.println(this);
System.out.println(this);
System.out.println(this);
System.out.println("transformImage -------------------------");
// optimize the dimension of the loaded image
Mat padded = optimizeImageDim(image);
padded.convertTo(padded, CvType.CV_32F);
// prepare the image planes to obtain the complex image
planes.add(padded);
planes.add(Mat.zeros(padded.size(), CvType.CV_32F));
// prepare a complex image for performing the dft
Core.merge(planes, complexImage);
// dft
Core.dft(complexImage, complexImage);
// optimize the image resulting from the dft operation
Mat magnitude = createOptimizedMagnitude(complexImage);
// show the result of the transformation as an image
transformedImage.setImage(mat2Image(magnitude));
// set a fixed width
transformedImage.setFitWidth(250);
// preserve image ratio
transformedImage.setPreserveRatio(true);
// enable the button for performing the antitransformation
antitransformButton.setDisable(false);
// disable the button for applying the dft
transformButton.setDisable(true);
}
/**
* The action triggered by pushing the button for apply the inverse dft to
* the loaded image
*/
@FXML
protected void antitransformImage()
{
System.out.println("antitransformImage -------------------------");
System.out.println(this);
System.out.println(this);
System.out.println(this);
System.out.println(this);
System.out.println(this);
System.out.println("antitransformImage -------------------------");
Core.idft(complexImage, complexImage);
Mat restoredImage = new Mat();
Core.split(complexImage, planes);
Core.normalize(planes.get(0), restoredImage, 0, 255, Core.NORM_MINMAX);
antitransformedImage.setImage(mat2Image(restoredImage));
// set a fixed width
antitransformedImage.setFitWidth(250);
// preserve image ratio
antitransformedImage.setPreserveRatio(true);
// disable the button for performing the antitransformation
antitransformButton.setDisable(true);
}
/**
* Optimize the image dimensions
*
* @param image
* the {@link Mat} to optimize
* @return the image whose dimensions have been optimized
*/
private Mat optimizeImageDim(Mat image)
{
// init
Mat padded = new Mat();
// get the optimal rows size for dft
int addPixelRows = Core.getOptimalDFTSize(image.rows());
// get the optimal cols size for dft
int addPixelCols = Core.getOptimalDFTSize(image.cols());
// apply the optimal cols and rows size to the image
Core.copyMakeBorder(image, padded, 0, addPixelRows - image.rows(), 0, addPixelCols - image.cols(),
Core.BORDER_CONSTANT, Scalar.all(0));
return padded;
}
/**
* Optimize the magnitude of the complex image obtained from the DFT, to
* improve its visualization
*
* @param complexImage
* the complex image obtained from the DFT
* @return the optimized image
*/
private Mat createOptimizedMagnitude(Mat complexImage)
{
// init
List<Mat> newPlanes = new ArrayList<>();
Mat mag = new Mat();
// split the comples image in two planes
Core.split(complexImage, newPlanes);
// compute the magnitude
Core.magnitude(newPlanes.get(0), newPlanes.get(1), mag);
// move to a logarithmic scale
Core.add(Mat.ones(mag.size(), CvType.CV_32F), mag, mag);
Core.log(mag, mag);
// optionally reorder the 4 quadrants of the magnitude image
shiftDFT(mag);
// normalize the magnitude image for the visualization since both JavaFX
// and OpenCV need images with value between 0 and 255
// convert back to CV_8UC1
mag.convertTo(mag, CvType.CV_8UC1);
Core.normalize(mag, mag, 0, 255, Core.NORM_MINMAX, CvType.CV_8UC1);
// you can also write on disk the resulting image...
// Imgcodecs.imwrite("../magnitude.png", mag);
return mag;
}
/**
* Reorder the 4 quadrants of the image representing the magnitude, after
* the DFT
*
* @param image
* the {@link Mat} object whose quadrants are to reorder
*/
private void shiftDFT(Mat image)
{
image = image.submat(new Rect(0, 0, image.cols() & -2, image.rows() & -2));
int cx = image.cols() / 2;
int cy = image.rows() / 2;
Mat q0 = new Mat(image, new Rect(0, 0, cx, cy));
Mat q1 = new Mat(image, new Rect(cx, 0, cx, cy));
Mat q2 = new Mat(image, new Rect(0, cy, cx, cy));
Mat q3 = new Mat(image, new Rect(cx, cy, cx, cy));
Mat tmp = new Mat();
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp);
q2.copyTo(q1);
tmp.copyTo(q2);
}
/**
* Set the current stage (needed for the FileChooser modal window)
*
* @param stage
* the stage
*/
public Stage getStage() {
return stage;
}
public void setStage(Stage stage)
{
this.stage = stage;
}
/**
* Convert a Mat object (OpenCV) in the corresponding Image for JavaFX
*
* @param frame
* the {@link Mat} representing the current frame
* @return the {@link Image} to show
*/
private Image mat2Image(Mat frame)
{
// create a temporary buffer
MatOfByte buffer = new MatOfByte();
// encode the frame in the buffer, according to the PNG format
Imgcodecs.imencode(".png", frame, buffer);
// build and return an Image created from the image encoded in the
// buffer
return new Image(new ByteArrayInputStream(buffer.toArray()));
}
}
Fourier.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.hoex.fourier.FourierController">
<left>
<VBox prefHeight="200.0" prefWidth="100.0" BorderPane.alignment="CENTER">
<children>
<ImageView fx:id="originalImage" fitHeight="150.0" fitWidth="200.0" pickOnBounds="true" preserveRatio="true" />
</children>
</VBox>
</left>
<right>
<VBox prefHeight="200.0" prefWidth="100.0" BorderPane.alignment="CENTER">
<children>
<ImageView fx:id="transformedImage" fitHeight="150.0" fitWidth="200.0" pickOnBounds="true" preserveRatio="true" />
<ImageView fx:id="antitransformedImage" fitHeight="150.0" fitWidth="200.0" pickOnBounds="true" preserveRatio="true" />
</children>
</VBox>
</right>
<bottom>
<HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<children>
<Button fx:id="loadButton" mnemonicParsing="false" onAction="#loadImage" text="Load Image">
<HBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</HBox.margin>
</Button>
<Button fx:id="transformButton" disable="true" mnemonicParsing="false" onAction="#transformImage" text="Apply transform">
<HBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</HBox.margin>
</Button>
<Button fx:id="antitransformButton" disable="true" mnemonicParsing="false" onAction="#antitransformImage" text="Apply anti transform">
<HBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</HBox.margin>
</Button>
</children>
</HBox>
</bottom>
</BorderPane>
运行应用程序并单击按钮,然后出现在控制台中。 FourierController是BEAN,但它们是不同的。我该如何解决?
Bean FourierController--------------
com.hoex.fourier.FourierController@48309481
Bean FourierController--------------
loadImage -------------------------
com.hoex.fourier.FourierController@b0b5062
loadImage -------------------------
答案 0 :(得分:1)
您使用context.getBean(FourierController.class)
从Spring IoC容器中请求一个控制器,然后再次使用fourierController.setRoot(FXMLLoader.load(...))
加载FXML,从而使FXMLLoader
再次实例化控制器类。
一点也不清楚为什么要通过方法调用设置root;只需将fx:id="root"
添加到FXML的根元素中,让FXMLLoader
以与所有其他元素相同的方式注入根元素。然后您的应用程序代码可以简单地
@Override
public void start(Stage primaryStage) throws Exception {
try {
ApplicationContext context = SpringApplication.run(App.class, args);
// Create a Scene
FourierController fourierController = context.getBean(FourierController.class);
System.out.println("App primaryStage -----------------");
System.out.println(primaryStage);
System.out.println("App primaryStage -----------------");
fourierController.setStage(primaryStage);
System.out.println("App set primaryStage -----------------");
System.out.println(fourierController.getStage());
System.out.println("App set primaryStage -----------------");
Scene scene = new Scene((Parent)fourierController.getRoot());
// Set the scene on the primary stage
primaryStage.setScene(scene);
// Any other shenanigans on the primary stage
primaryStage.show();
System.out.println("App Root ---------------------");
System.out.println(primaryStage.getScene().getRoot());
System.out.println(fourierController.getRoot());
System.out.println("App Root ---------------------");
} catch(Exception e) {
e.printStackTrace();
}
}