Saya sedang mengembangkan program penelusuran dengan menempatkan titik ke titik anatomis pada Xray. Masalah saya adalah, saya mencoba memperbesar gambar sinar-X saya (Imageview) sementara mouse saya melayang ke atasnya dan menampilkan Imageview lain. Saya ingin mouse saya membuat persegi panjang virtual di sekitarnya dan tetap berada di tengah saat memindahkan dan mentransfer gambar langsung itu ke Imageview kecil lainnya, sejauh ini saya telah melakukan ini tetapi ada beberapa gangguan. Persegi panjang saya tidak mengikuti mouse saya persis seperti yang seharusnya, dan kesalahan semakin cepat ketika saya pindah ke sudut, Apa yang bisa Anda sarankan? Saya membagikan kesalahan dan kode saya untuk mengklarifikasi semua itu.

Mungkin saya harus membuat bentuk persegi panjang dan meletakkannya di sekitar posisi mouse dan memotong gambar secara langsung, sesuai dengan zoomedImageview, dan menampilkannya sepanjang waktu, tetapi saya terjebak dalam hal ini.

Masalah utamanya adalah, posisi mouse dan posisi tengah zoomedImageview harus selalu bertepatan.

enter image description here

Xray Imageview Fitwidth-height diperbesar 800x800Imageview Fitwidth-height adalah 250x250

public class DrawingController {

        @FXML 
    ImageView xrayImage;
        
         @FXML
    ImageView zoomedImage;

   public void initialize()
    {

   xrayImage.setOnMouseMoved(e -> {    //HOVERING ON XRAY
   
PixelReader reader = XrayImageview.getImage().getPixelReader();   
WritableImage newImage = new WritableImage(reader,

(int) e.getX(),  //x and y is picked according to hovering mouse position
   (int) e.getY(),
   (int) 250,     // 250x250 rectangle is requested.
   (int) 250);

zoomedImage.setImage(newImage);  // Displaying zoomed image

        });
}}

Dan file FXML saya adalah:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane prefHeight="913.0" prefWidth="1238.0" xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1" fx:controller="main.java.controllers.DrawingController">
   <children>
      <ImageView fitHeight="800.0" fitWidth="800.0" layoutX="418.0" layoutY="33.0" pickOnBounds="true" preserveRatio="true" fx:id="xrayImage">
         <image>
            <Image url="@threatCare.png" />
         </image>
      </ImageView>
      <ImageView fx:id="zoomedImage" fitHeight="250.0" fitWidth="250.0" layoutX="108.0" layoutY="433.0" pickOnBounds="true" preserveRatio="true" />
   </children>
</AnchorPane>

Dan kelas Utama:

package main.java;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
import main.java.database.DatabaseCreator;

import javax.swing.text.html.ImageView;
import java.awt.*;

public class Runner extends Application {
    @Override
    public void start(Stage primaryStage) throws Exception{
     
        Parent root = FXMLLoader.load(getClass().getResource("../resources/DrawingPanel.fxml"));

        primaryStage.setTitle("TreatCare Software Systems");
         Scene scene = new Scene(root,1200,950);
        primaryStage.setScene(scene);
        primaryStage.setMinWidth(1200);
        primaryStage.setMinHeight(950);
        primaryStage.setMaximized(true);
        primaryStage.setOnCloseRequest( e -> SystemClose());
        primaryStage.show();
    }

    private void SystemClose(){
        System.exit(0);         
    }

    public static void main(String[] args){
        launch(args);
    }
}
-1
Özden 19 September 2021, 19:52

2 jawaban

Jawaban Terbaik

Anda menskalakan gambar Anda, jadi Anda perlu mengonversi koordinat mouse Anda sesuai dengan penskalaan itu.

Dari file .fxml Anda:

<ImageView fitHeight="800.0" fitWidth="800.0" layoutX="418.0" layoutY="33.0" pickOnBounds="true" preserveRatio="true" fx:id="xrayImage">

Ada tiga atribut di baris itu yang menskalakan gambar:

  • fitWidth="800.0" - menskalakan gambar hingga lebar 800 piksel
  • fitHeight="800.0" - menskalakan gambar hingga setinggi 800 piksel
  • preserveRatio="true" - mengesampingkan semua penskalaan sehingga gambar selalu memiliki skala yang sama di kedua dimensi

Jadi, Anda perlu mengalikan koordinat mouse Anda dengan yang berikut:

xrayImage.setOnMouseMoved(e -> {    //HOVERING ON XRAY
    Image image = xrayImage.getImage();

    double x = e.getX();
    double y = e.getY();
    double xScale = (xrayImage.getFitWidth() > 0 ?
        image.getWidth() / xrayImage.getFitWidth() : 1);
    double yScale = (xrayImage.getFitHeight() > 0 ?
        image.getHeight() / xrayImage.getFitHeight() : 1);
    if (xrayImage.isPreserveRatio()) {
        double scale = Math.max(xScale, yScale);
        x *= scale;
        y *= scale;
    } else {
        x *= xScale;
        y *= yScale;
    }

    x = Math.max(0, x - 125);
    y = Math.max(0, y - 125);
    double width = Math.min(image.getWidth() - x, 250);
    double height = Math.min(image.getHeight() - y, 250);

    PixelReader reader = image.getPixelReader();   
    WritableImage newImage = new WritableImage(reader,
        (int) x, (int) y, (int) width, (int) height);

    zoomedImage.setImage(newImage);  // Displaying zoomed image
});
2
VGR 21 September 2021, 23:28

Saya menambahkan Panel ke DrawingPanel.fxml. Tujuan dari Pane adalah untuk menunjukkan batas area yang dipotong (penanda):

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.StackPane?>

<AnchorPane prefHeight="913.0" prefWidth="1238.0" xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1" 
                                                                            fx:controller="DrawingController">
   <children>
      <StackPane layoutX="418.0" layoutY="33.0">
         <children>
            <ImageView  fitHeight="800.0" fitWidth="800.0" preserveRatio="true" pickOnBounds="true" fx:id="xrayImagePane">
               <image>         
                <Image url="https://www.almanac.com/sites/default/files/image_nodes/cosmos-flower.jpg" />
               </image>
            </ImageView>
            <!-- Stack a Pane over the ImageView. Add the marker to this Pane -->
            <Pane fx:id="markerPane" prefHeight="200.0" prefWidth="200.0" />
         </children>
      </StackPane>
      <ImageView fx:id="croppedImageView" fitHeight="250.0" fitWidth="250.0" layoutX="108.0" layoutY="433.0" pickOnBounds="true" preserveRatio="true" />
   </children>
</AnchorPane>

Pengontrol menambahkan dan memperbarui penanda dan memperbarui gambar yang dipotong. Saya meminjam beberapa kode dari jawaban VGR untuk menangani skala, tetapi perhatikan penggunaan getLayoutBounds() untuk menghitung skala :

import javafx.fxml.FXML;
import javafx.geometry.Bounds;
import javafx.scene.image.*;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;

public class DrawingController {

    @FXML
    ImageView xrayImagePane;
    private Image fullImage;
    private PixelReader reader;

    @FXML
    Pane markerPane;
    private Rectangle marker;

    @FXML
    ImageView croppedImageView;

    private static int ZOOM_WONDOW_SIZE = 250;
    private static Color MARKER_COLOR  = Color.BLUE;

    @FXML
    public void initialize(){

        marker = new Rectangle(0,0, ZOOM_WONDOW_SIZE, ZOOM_WONDOW_SIZE);
        marker.setStroke(MARKER_COLOR);
        marker.setFill(Color.TRANSPARENT);
        marker.setStrokeWidth(3);
        markerPane.getChildren().add(marker);

        fullImage = xrayImagePane.getImage();
        reader = fullImage.getPixelReader();

        markerPane.setOnMouseMoved(e -> {
            updateMarker(e.getX(), e.getY());
            updateZoomImage();
        });
    }

    //update marker location based on mouse location
    private void updateMarker(double x, double y) {
        //use layout bounds because you do not know if the actual size is xrayImagePane.getFitWidth()
        //or fullImage.getWidth()
        Bounds imageViewBounds = xrayImagePane.getLayoutBounds();
        double imageWidth = imageViewBounds.getWidth();
        double newX= Math.max(0, x - ZOOM_WONDOW_SIZE/2 );
        newX =  newX + ZOOM_WONDOW_SIZE >= imageWidth ?  imageWidth - ZOOM_WONDOW_SIZE : newX;

        double imageHeight = imageViewBounds.getHeight();
        double newY = Math.max(0, y - ZOOM_WONDOW_SIZE/2 );
        newY=  newY + ZOOM_WONDOW_SIZE >= imageHeight ?  imageHeight - ZOOM_WONDOW_SIZE : newY;

        marker.setX(newX);
        marker.setY(newY);
    }

    //update zoomed image based on marker and scale
    private void updateZoomImage() {

        //adapted from VGR's answer https://stackoverflow.com/a/69273511/3992939
        double x = marker.getX();
        double y = marker.getY();
        double width = marker.getWidth();
        double height= marker.getHeight();
        //use layout bounds because you do not know if the actual size is xrayImagePane.getFitWidth()
        //or fullImage.getWidth()
        Bounds imageViewBounds = xrayImagePane.getLayoutBounds();

        double xScale = xrayImagePane.getFitWidth() > 0 ?
                            fullImage.getWidth() / imageViewBounds.getWidth() : 1;
        double yScale = xrayImagePane.getFitHeight() > 0 ?
                           fullImage.getHeight() / imageViewBounds.getHeight(): 1;
        if (xrayImagePane.isPreserveRatio()) {
            double scale = Math.min(xScale, yScale);
            x *= scale;
            y *= scale;
            width *= scale;
            height *= scale;
        } else {
            x *= xScale;
            y *= yScale;
            width *= xScale;
            height *= yScale;
        }

        WritableImage croppedImage = new WritableImage(reader,
                (int) x,
                (int) y,
                (int) width,
                (int) height
                );
        croppedImageView.setImage(croppedImage); 
    }
}

Uji menggunakan

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.*;
import javafx.stage.Stage;

public class Runner extends Application {
    @Override
    public void start(Stage primaryStage) throws Exception{

        Parent root = FXMLLoader.load(getClass().getResource("DrawingPanel.fxml"));

        primaryStage.setTitle("TreatCare Software Systems");
         Scene scene = new Scene(root);
        primaryStage.setScene(scene);

        primaryStage.setOnCloseRequest( e -> SystemClose());
        primaryStage.show();
    }

    private void SystemClose(){
        System.exit(0);
    }

    public static void main(String[] args){
        launch(args);
    }
}

enter image description here

0
c0der 22 September 2021, 17:40