From 5eb7c51a9707f18a8e0f760a3fbdfd25bbdfaaab Mon Sep 17 00:00:00 2001 From: sige Date: Sat, 13 Apr 2024 17:13:40 +0800 Subject: [PATCH] ~ --- pom.xml | 5 + .../com/iflytop/digester/StartResetTaskThread.java | 24 ++-- .../iflytop/digester/camera/DiComBaslerCamera.java | 129 +++++++++++++++++++++ .../iflytop/digester/deviceinstance/Camera.java | 68 +++++++++++ 4 files changed, 212 insertions(+), 14 deletions(-) create mode 100644 src/main/java/com/iflytop/digester/camera/DiComBaslerCamera.java diff --git a/pom.xml b/pom.xml index 3a8e027..27c2f7a 100644 --- a/pom.xml +++ b/pom.xml @@ -52,6 +52,11 @@ freemarker 2.3.31 + + org.opencv + opencv-420 + 4.2.0 + diff --git a/src/main/java/com/iflytop/digester/StartResetTaskThread.java b/src/main/java/com/iflytop/digester/StartResetTaskThread.java index 6f09447..a64fb35 100644 --- a/src/main/java/com/iflytop/digester/StartResetTaskThread.java +++ b/src/main/java/com/iflytop/digester/StartResetTaskThread.java @@ -8,11 +8,8 @@ import com.iflytop.digester.underframework.dao.model.UfMdbOption; import com.iflytop.digester.underframework.dao.model.UfMdbRuntimeVariable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import java.util.HashMap; import java.util.List; -import java.util.Map; - public class StartResetTaskThread extends Thread { // logger public static final Logger LOG = LoggerFactory.getLogger(StartResetTaskThread.class); @@ -28,15 +25,14 @@ public class StartResetTaskThread extends Thread { this.setProgressMessage("设备初始化..."); UfCmdSnippetExecutor.execute("StartResetInitDevices"); -// this.setupHeatingSlotCover(); -// this.setupPeristalticPump(); + this.setupHeatingSlotCover(); + this.setupPeristalticPump(); if ( this.isErrorTubeRackRequired ) { this.setupErrorTubeRack(); } -// this.setProgressMessage("设备初始化 : 相机"); -// DiActCameraBasler camera = this.getActuator(MyDevice.ACT_CAMERA, DiActCameraBasler.class); -// camera.setEnable(true); + this.setProgressMessage("设备初始化 : 相机"); + device.camera.enable(); this.setProgressMessage("设备初始化 : 定时刷新加热盘温度"); device.heatingTurntable.temperatureMonitorStart(); @@ -50,8 +46,8 @@ public class StartResetTaskThread extends Thread { // 设置蠕动泵 private void setupPeristalticPump() { for ( int i=0; i<16; i++ ) { -// this.setProgressMessage("设备初始化 : 初始化蠕动泵 " + (i+1) + "/16"); -// UfCmdSnippetExecutor.execute(String.format("PeristalticPumpEnable.%d",i)); + this.setProgressMessage("设备初始化 : 初始化蠕动泵 " + (i+1) + "/16"); + UfCmdSnippetExecutor.execute(String.format("PeristalticPumpEnable.%d",i)); } Boolean enableSetup = UfApplication.getApp().getEnv().getProperty("app.liquidPeristalticPumpPipeSetupEnable",Boolean.class); @@ -70,10 +66,10 @@ public class StartResetTaskThread extends Thread { Device device = Device.getInstance(); var tubes = List.of(0,4, 3,2, 15,11, 12,13, 1,5, 6,7, 14,10, 9,8); for ( int i=0; i<8; i++ ) { -// this.setProgressMessage("设备初始化 : 初始化加液管路 " + (i+1) + "/8"); -// var tubeList = tubes.subList(i*2, i*2+2); -// var pumpList = List.of(2*i, 2*i+1); -// device.liquidAddition.addLiquidToTubes(tubeList, pumpList, 10000); + this.setProgressMessage("设备初始化 : 初始化加液管路 " + (i+1) + "/8"); + var tubeList = tubes.subList(i*2, i*2+2); + var pumpList = List.of(2*i, 2*i+1); + device.liquidAddition.addLiquidToTubes(tubeList, pumpList, 10000); } // 加液管充满, 需要取出试管架 diff --git a/src/main/java/com/iflytop/digester/camera/DiComBaslerCamera.java b/src/main/java/com/iflytop/digester/camera/DiComBaslerCamera.java new file mode 100644 index 0000000..ceb7035 --- /dev/null +++ b/src/main/java/com/iflytop/digester/camera/DiComBaslerCamera.java @@ -0,0 +1,129 @@ +package com.iflytop.digester.camera; +public class DiComBaslerCamera { + public static final int ACCESS_MODE_MONITOR = 0; + public static final int ACCESS_MODE_CONTROL = 1; + public static final int ACCESS_MODE_STREAM = (1 << 1); + public static final int ACCESS_MODE_EVENT = (1 << 2); + public static final int ACCESS_MODE_EXCLUSIVE = (1 << 3); + + public static class GrabResult { + public byte[] imageBuffer; + public int payloadType; + public int pixelType; + public int sizeX; + public int sizeY; + public int offsetX; + public int offsetY; + public int paddingX; + public int paddingY; + public long PayloadSize; + public int ErrorCode; + } + + /** + * Initializes the pylon runtime system. + */ + public native void initialize(); + + /** + * Enumerates all camera devices. + * @return The number of found devices. + */ + public native int enumerateDevices(); + + /** + * Terminates the pylon runtime system. + */ + public native void terminate(); + + /** + * Creates a camera device by index. + * @param index The index of the camera device. + * @return The handle of the camera device. + */ + public native long createDeviceByIndex(int index); + + /** + * Opens the camera device. + * @param hDev The handle of the camera device. + * @param accessMode The access mode. + */ + public native void deviceOpen(long hDev, int accessMode); + + /** + * Checks if a camera device feature is readable. + * @param hDev The handle of the camera device. + * @param name The name of the feature. + * @return true if the feature is readable, false otherwise. + */ + public native boolean deviceFeatureIsReadable(long hDev, String name); + + /** + * Read a camera device feature to a string. + * @param hDev The handle of the camera device. + * @param name The name of the feature. + * @param size The size of the string buffer. + * @return The string value of the feature. + */ + public native String deviceFeatureToString(long hDev, String name, int size); + + /** + * Checks if a camera device feature is available. + * @param hDev The handle of the camera device. + * @param name The name of the feature. + * @return true if the feature is available, false otherwise. + */ + public native boolean deviceFeatureIsAvailable(long hDev, String name); + + /** + * Writes a camera device feature from a string. + * @param hDev The handle of the camera device. + * @param name The name of the feature. + * @param value The value of the feature. + */ + public native void deviceFeatureFromString(long hDev, String name, String value); + + /** + * Checks if a camera device feature is writable. + * @param hDev The handle of the camera device. + * @param name The name of the feature. + * @return true if the feature is writable, false otherwise. + */ + public native boolean deviceFeatureIsWritable(long hDev, String name); + + /** + * Writes a camera device feature from an integer. + * @param hDev The handle of the camera device. + * @param name The name of the feature. + * @param value The value of the feature. + */ + public native void deviceSetIntegerFeature(long hDev, String name, int value); + + /** + * Reads a camera device feature to an integer. + * @param hDev The handle of the camera device. + * @param name The name of the feature. + * @return The integer value of the feature. + */ + public native int deviceGetIntegerFeatureInt32(long hDev, String name); + + /** + * Grabs a single frame from the camera device. + * @param hDev The handle of the camera device. + * @param channel The channel index. + * @return The grab result. + */ + public native GrabResult deviceGrabSingleFrame(long hDev, int channel); + + /** + * Closes the camera device. + * @param hDev The handle of the camera device. + */ + public native void deviceClose(long hDev); + + /** + * Destroys the camera device. + * @param hDev The handle of the camera device. + */ + public native void destroyDevice(long hDev); +} diff --git a/src/main/java/com/iflytop/digester/deviceinstance/Camera.java b/src/main/java/com/iflytop/digester/deviceinstance/Camera.java index 5abc97c..fb68da7 100644 --- a/src/main/java/com/iflytop/digester/deviceinstance/Camera.java +++ b/src/main/java/com/iflytop/digester/deviceinstance/Camera.java @@ -1,6 +1,74 @@ package com.iflytop.digester.deviceinstance; +import com.iflytop.digester.camera.DiComBaslerCamera; import org.springframework.stereotype.Component; +import org.opencv.core.CvType; +import org.opencv.core.Mat; @Component public class Camera { + // camera + private static DiComBaslerCamera pylon = null; + // index + protected Integer index; + // channel + protected Integer channel; + // camera handle + private long cam = -1; + // get pylon + private DiComBaslerCamera getPylon() { + if ( null == Camera.pylon ) { + Camera.pylon = new DiComBaslerCamera(); + Camera.pylon.initialize(); + } + return Camera.pylon; + } + + // enable + public void enable( ) { + if ( -1 != this.cam ) { + return ; + } + + var pylon = this.getPylon(); + int count = pylon.enumerateDevices(); + if ( this.index >= count ) { + throw new RuntimeException("Camera index out of range"); + } + + this.cam = pylon.createDeviceByIndex(this.index); + pylon.deviceOpen(this.cam, DiComBaslerCamera.ACCESS_MODE_CONTROL | DiComBaslerCamera.ACCESS_MODE_STREAM); + + boolean isFeatureReadable = pylon.deviceFeatureIsReadable(cam, "DeviceModelName"); + if ( isFeatureReadable ) { + String name = pylon.deviceFeatureToString(cam, "DeviceModelName", 256); + } + + pylon.deviceFeatureFromString(cam, "PixelFormat", "Mono8"); + pylon.deviceFeatureFromString(cam, "TriggerSelector", "AcquisitionStart"); + pylon.deviceFeatureFromString(cam, "TriggerMode", "Off"); + pylon.deviceFeatureFromString(cam, "TriggerSelector", "FrameStart"); + pylon.deviceFeatureFromString(cam, "TriggerMode", "Off"); + pylon.deviceSetIntegerFeature(cam, "GevSCPSPacketSize", 1500); + pylon.deviceFeatureFromString(cam, "ExposureAuto", "Off"); + pylon.deviceSetIntegerFeature(cam, "ExposureTimeRaw", 27218); + } + + // disable + public void disable() { + if ( -1 == this.cam ) { + return ; + } + var pylon = this.getPylon(); + pylon.deviceClose(this.cam); + this.cam = -1; + } + + // grab + public Mat grabToMat () { + var pylon = this.getPylon(); + var result = pylon.deviceGrabSingleFrame(this.cam, this.channel); + Mat frameMat = new Mat(result.sizeY, result.sizeX, CvType.CV_8UC1); + frameMat.put(0, 0, result.imageBuffer); + return frameMat; + } }