为什么不是豆的数量?

时间:2016-05-31 09:22:29

标签: spring javafx-8

我看到了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 -------------------------

1 个答案:

答案 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();
    }
}