海康工业相机对接彩色视频流
This commit is contained in:
@@ -10,7 +10,7 @@ import top.wms.admin.controller.weighManage.ah.ScaleWebSocketHandler;
|
|||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSocket
|
@EnableWebSocket
|
||||||
public class webSocket implements WebSocketConfigurer {
|
public class WebSocketConfig implements WebSocketConfigurer {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private CameraWebSocketHandler cameraWebSocketHandler;
|
private CameraWebSocketHandler cameraWebSocketHandler;
|
||||||
@@ -19,7 +19,7 @@ public class webSocket implements WebSocketConfigurer {
|
|||||||
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
|
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
|
||||||
// 注册WebSocket端点,允许所有跨域请求
|
// 注册WebSocket端点,允许所有跨域请求
|
||||||
registry.addHandler(new ScaleWebSocketHandler(), "/ws/scale").setAllowedOrigins("*");
|
registry.addHandler(new ScaleWebSocketHandler(), "/ws/scale").setAllowedOrigins("*");
|
||||||
// 注册海康相机WebSocket端点
|
// 注册海康相机1 WebSocket端点
|
||||||
registry.addHandler(cameraWebSocketHandler, "/ws/camera").setAllowedOrigins("*");
|
registry.addHandler(cameraWebSocketHandler, "/ws/camera").setAllowedOrigins("*");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,8 +76,6 @@ public class CameraService {
|
|||||||
if (null == stDeviceInfo) {
|
if (null == stDeviceInfo) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
log.info("[camera {}}", i++);
|
|
||||||
printDeviceInfo(stDeviceInfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 默认选择第一个设备
|
// 默认选择第一个设备
|
||||||
@@ -110,6 +108,15 @@ public class CameraService {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 设置Bayer转换质量,用于彩色相机
|
||||||
|
log.info("Setting Bayer convert quality...");
|
||||||
|
nRet = MvCameraControl.MV_CC_SetBayerCvtQuality(hCamera, 1);
|
||||||
|
if (MV_OK != nRet) {
|
||||||
|
log.error("Set Bayer convert quality fail! nRet [0x{0}]", Integer.toHexString(nRet));
|
||||||
|
closeCamera();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
log.info("Camera initialized successfully");
|
log.info("Camera initialized successfully");
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -140,7 +147,6 @@ public class CameraService {
|
|||||||
int nRet = MvCameraControl.MV_CC_RegisterImageCallBack(hCamera, new CameraImageCallBack() {
|
int nRet = MvCameraControl.MV_CC_RegisterImageCallBack(hCamera, new CameraImageCallBack() {
|
||||||
@Override
|
@Override
|
||||||
public int OnImageCallBack(byte[] bytes, MV_FRAME_OUT_INFO mv_frame_out_info) {
|
public int OnImageCallBack(byte[] bytes, MV_FRAME_OUT_INFO mv_frame_out_info) {
|
||||||
printFrameInfo(mv_frame_out_info);
|
|
||||||
processImage(bytes, mv_frame_out_info);
|
processImage(bytes, mv_frame_out_info);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -226,7 +232,8 @@ public class CameraService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理图像数据
|
* 处理图像数据
|
||||||
* @param bytes 原始图像数据
|
*
|
||||||
|
* @param bytes 原始图像数据
|
||||||
* @param frameInfo 帧信息
|
* @param frameInfo 帧信息
|
||||||
*/
|
*/
|
||||||
private void processImage(byte[] bytes, MV_FRAME_OUT_INFO frameInfo) {
|
private void processImage(byte[] bytes, MV_FRAME_OUT_INFO frameInfo) {
|
||||||
@@ -242,41 +249,65 @@ public class CameraService {
|
|||||||
}
|
}
|
||||||
lastFrameTime = currentTime;
|
lastFrameTime = currentTime;
|
||||||
|
|
||||||
// 打印帧信息,以便调试
|
int dataSizeForRGB = frameInfo.width * frameInfo.height * 3; // RGB每个像素3字节
|
||||||
printFrameInfo(frameInfo);
|
byte[] pDataForRGB = new byte[dataSizeForRGB];
|
||||||
|
|
||||||
// 对于黑白相机(MV-CE050-30GM),数据是单通道灰度格式
|
// 初始化像素转换参数
|
||||||
// 将原始灰度数据转换为BufferedImage
|
MV_CC_PIXEL_CONVERT_PARAM_EX stConvertParam = new MV_CC_PIXEL_CONVERT_PARAM_EX();
|
||||||
BufferedImage image = new BufferedImage(frameInfo.width, frameInfo.height, BufferedImage.TYPE_BYTE_GRAY);
|
|
||||||
image.getRaster().setDataElements(0, 0, frameInfo.width, frameInfo.height, bytes);
|
// 使用实际的width和height,避免ExtendHeight为0的问题
|
||||||
|
stConvertParam.width = frameInfo.width;
|
||||||
|
stConvertParam.height = frameInfo.height;
|
||||||
|
stConvertParam.srcData = bytes;
|
||||||
|
stConvertParam.srcDataLen = frameInfo.frameLen;
|
||||||
|
stConvertParam.srcPixelType = frameInfo.pixelType;
|
||||||
|
stConvertParam.dstPixelType = MvGvspPixelType.PixelType_Gvsp_RGB8_Packed;
|
||||||
|
stConvertParam.dstBuffer = pDataForRGB;
|
||||||
|
stConvertParam.dstBufferSize = dataSizeForRGB;
|
||||||
|
|
||||||
|
// 尝试进行像素格式转换
|
||||||
|
int nRet = MvCameraControl.MV_CC_ConvertPixelTypeEx(hCamera, stConvertParam);
|
||||||
|
if (MV_OK != nRet) {
|
||||||
|
log.error("Convert PixelType fail, errCode: {}, srcPixelType: {}, width: {}, height: {}",
|
||||||
|
Integer.toHexString(nRet),
|
||||||
|
frameInfo.pixelType.getnValue(),
|
||||||
|
frameInfo.width,
|
||||||
|
frameInfo.height);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将RGB数据转换为BufferedImage
|
||||||
|
BufferedImage image = new BufferedImage(frameInfo.width, frameInfo.height, BufferedImage.TYPE_3BYTE_BGR);
|
||||||
|
image.getRaster().setDataElements(0, 0, frameInfo.width, frameInfo.height, pDataForRGB);
|
||||||
|
|
||||||
// 压缩图像为JPEG格式
|
// 压缩图像为JPEG格式
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
ImageIO.write(image, "jpeg", baos);
|
ImageIO.write(image, "jpeg", baos);
|
||||||
byte[] compressedData = baos.toByteArray();
|
byte[] compressedData = baos.toByteArray();
|
||||||
baos.close();
|
baos.close();
|
||||||
|
|
||||||
log.debug("Original size: {} bytes, Compressed size: {} bytes, Compression ratio: {:.2f}%",
|
log.debug("Original size: {} bytes, Converted size: {} bytes, Compressed size: {} bytes, Compression ratio: {:.2f}%",
|
||||||
bytes.length, compressedData.length, (1 - (double)compressedData.length / bytes.length) * 100);
|
bytes.length, pDataForRGB.length, compressedData.length, (1 - (double) compressedData.length / bytes.length) * 100);
|
||||||
|
|
||||||
// 创建包含图像尺寸信息和压缩数据的消息
|
// 创建包含图像尺寸信息和压缩数据的消息
|
||||||
// 消息格式: [width(4 bytes)][height(4 bytes)][image data]
|
// 消息格式: [width(4 bytes)][height(4 bytes)][image data]
|
||||||
byte[] message = new byte[8 + compressedData.length];
|
byte[] message = new byte[8 + compressedData.length];
|
||||||
|
|
||||||
// 写入宽度和高度(使用小端序)
|
// 写入宽度和高度(使用小端序)
|
||||||
message[0] = (byte) (frameInfo.width & 0xFF);
|
message[0] = (byte) (frameInfo.width & 0xFF);
|
||||||
message[1] = (byte) ((frameInfo.width >> 8) & 0xFF);
|
message[1] = (byte) ((frameInfo.width >> 8) & 0xFF);
|
||||||
message[2] = (byte) ((frameInfo.width >> 16) & 0xFF);
|
message[2] = (byte) ((frameInfo.width >> 16) & 0xFF);
|
||||||
message[3] = (byte) ((frameInfo.width >> 24) & 0xFF);
|
message[3] = (byte) ((frameInfo.width >> 24) & 0xFF);
|
||||||
|
|
||||||
message[4] = (byte) (frameInfo.height & 0xFF);
|
message[4] = (byte) (frameInfo.height & 0xFF);
|
||||||
message[5] = (byte) ((frameInfo.height >> 8) & 0xFF);
|
message[5] = (byte) ((frameInfo.height >> 8) & 0xFF);
|
||||||
message[6] = (byte) ((frameInfo.height >> 16) & 0xFF);
|
message[6] = (byte) ((frameInfo.height >> 16) & 0xFF);
|
||||||
message[7] = (byte) ((frameInfo.height >> 24) & 0xFF);
|
message[7] = (byte) ((frameInfo.height >> 24) & 0xFF);
|
||||||
|
|
||||||
// 写入压缩后的图像数据
|
// 写入压缩后的图像数据
|
||||||
System.arraycopy(compressedData, 0, message, 8, compressedData.length);
|
System.arraycopy(compressedData, 0, message, 8, compressedData.length);
|
||||||
|
|
||||||
// 发送图像数据到所有连接的WebSocket客户端
|
// 发送图像数据到所有连接的WebSocket客户端
|
||||||
for (WebSocketSession session : webSocketSessions.values()) {
|
for (WebSocketSession session : webSocketSessions.values()) {
|
||||||
if (session.isOpen()) {
|
if (session.isOpen()) {
|
||||||
@@ -346,59 +377,4 @@ public class CameraService {
|
|||||||
return isRunning;
|
return isRunning;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 打印设备信息
|
|
||||||
* @param stDeviceInfo 设备信息
|
|
||||||
*/
|
|
||||||
private void printDeviceInfo(MV_CC_DEVICE_INFO stDeviceInfo) {
|
|
||||||
if (null == stDeviceInfo) {
|
|
||||||
log.error("stDeviceInfo is null");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((stDeviceInfo.transportLayerType == MV_GIGE_DEVICE) || (stDeviceInfo.transportLayerType == MV_GENTL_GIGE_DEVICE)) {
|
|
||||||
log.info("\tCurrentIp: {}", stDeviceInfo.gigEInfo.currentIp);
|
|
||||||
log.info("\tModel: {}", stDeviceInfo.gigEInfo.modelName);
|
|
||||||
log.info("\tUserDefinedName: {}", stDeviceInfo.gigEInfo.userDefinedName);
|
|
||||||
} else if (stDeviceInfo.transportLayerType == MV_USB_DEVICE) {
|
|
||||||
log.info("\tUserDefinedName: {}", stDeviceInfo.usb3VInfo.userDefinedName);
|
|
||||||
log.info("\tSerial Number: {}", stDeviceInfo.usb3VInfo.serialNumber);
|
|
||||||
log.info("\tDevice Number: {}", stDeviceInfo.usb3VInfo.deviceNumber);
|
|
||||||
} else if (stDeviceInfo.transportLayerType == MV_GENTL_CAMERALINK_DEVICE) {
|
|
||||||
log.info("\tUserDefinedName: {}", stDeviceInfo.cmlInfo.userDefinedName);
|
|
||||||
log.info("\tSerial Number: {}", stDeviceInfo.cmlInfo.serialNumber);
|
|
||||||
log.info("\tDevice Number: {}", stDeviceInfo.cmlInfo.DeviceID);
|
|
||||||
} else if (stDeviceInfo.transportLayerType == MV_GENTL_CXP_DEVICE) {
|
|
||||||
log.info("\tUserDefinedName: {}", stDeviceInfo.cxpInfo.userDefinedName);
|
|
||||||
log.info("\tSerial Number: {}", stDeviceInfo.cxpInfo.serialNumber);
|
|
||||||
log.info("\tDevice Number: {}", stDeviceInfo.cxpInfo.DeviceID);
|
|
||||||
} else if (stDeviceInfo.transportLayerType == MV_GENTL_XOF_DEVICE) {
|
|
||||||
log.info("\tUserDefinedName: {}", stDeviceInfo.xofInfo.userDefinedName);
|
|
||||||
log.info("\tSerial Number: {}", stDeviceInfo.xofInfo.serialNumber);
|
|
||||||
log.info("\tDevice Number: {}", stDeviceInfo.xofInfo.DeviceID);
|
|
||||||
} else {
|
|
||||||
log.error("Device is not supported! ");
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info("\tAccessible: {}", MvCameraControl.MV_CC_IsDeviceAccessible(stDeviceInfo, MV_ACCESS_Exclusive));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 打印帧信息
|
|
||||||
* @param stFrameInfo 帧信息
|
|
||||||
*/
|
|
||||||
private void printFrameInfo(MV_FRAME_OUT_INFO stFrameInfo) {
|
|
||||||
if (null == stFrameInfo) {
|
|
||||||
log.error("stFrameInfo is null");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBuilder frameInfo = new StringBuilder("");
|
|
||||||
frameInfo.append(("\tFrameNum[" + stFrameInfo.frameNum + "]"));
|
|
||||||
frameInfo.append("\tWidth[" + stFrameInfo.width + "]");
|
|
||||||
frameInfo.append("\tHeight[" + stFrameInfo.height + "]");
|
|
||||||
frameInfo.append(String.format("\tPixelType[%#x]", stFrameInfo.pixelType.getnValue()));
|
|
||||||
|
|
||||||
log.debug(frameInfo.toString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -140,36 +140,20 @@ public class ConvertPixelType
|
|||||||
// Choose a device to operate
|
// Choose a device to operate
|
||||||
int camIndex = -1;
|
int camIndex = -1;
|
||||||
|
|
||||||
while (true)
|
while (true) {
|
||||||
{
|
try {
|
||||||
System.out.print("Please input camera index:");
|
camIndex = 0;
|
||||||
if (scanner.hasNextInt())
|
if ((camIndex >= 0 && camIndex < stDeviceList.size()) || -1 == camIndex) {
|
||||||
{
|
break;
|
||||||
try
|
} else {
|
||||||
{
|
System.out.println("Input error: " + camIndex + " Over Range:( 0 - " + (stDeviceList.size() - 1) + " )");
|
||||||
camIndex = scanner.nextInt();
|
|
||||||
if ((camIndex >= 0 && camIndex < stDeviceList.size()) || -1 == camIndex)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
System.out.println("Input error: " + camIndex + " Over Range:( 0 - " + (stDeviceList.size()-1) + " )");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
} catch (Exception e) {
|
||||||
{
|
System.out.println("Input not number.");
|
||||||
System.out.println("Input not number.");
|
camIndex = -1;
|
||||||
camIndex = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
camIndex = -1;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (-1 == camIndex) {
|
if (-1 == camIndex) {
|
||||||
System.out.println("Input error.exit");
|
System.out.println("Input error.exit");
|
||||||
@@ -328,7 +312,7 @@ public class ConvertPixelType
|
|||||||
System.err.printf("set Bayer convert quality fail! nRet [0x%x]\n", nRet);
|
System.err.printf("set Bayer convert quality fail! nRet [0x%x]\n", nRet);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
System.out.println("临时日志: frameInfo.width = " + stImageInfo.width + ", frameInfo.height = " + stImageInfo.height + ", frameInfo.ExtendWidth = " + stImageInfo.ExtendWidth + ", frameInfo.ExtendHeight = " + stImageInfo.ExtendHeight + ", frameInfo.frameLen = " + stImageInfo.frameLen + ", frameInfo.pixelType = " + stImageInfo.pixelType);
|
||||||
int dataSizeForRGB = stImageInfo.width * stImageInfo.height * 3; // every RGB pixel takes 3 bytes
|
int dataSizeForRGB = stImageInfo.width * stImageInfo.height * 3; // every RGB pixel takes 3 bytes
|
||||||
byte[] pDataForRGB = new byte[dataSizeForRGB];
|
byte[] pDataForRGB = new byte[dataSizeForRGB];
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user