海康工业相机对接彩色视频流

This commit is contained in:
zc
2026-03-11 15:05:14 +08:00
parent 4802e11f7c
commit c80dce6419
3 changed files with 66 additions and 106 deletions

View File

@@ -10,7 +10,7 @@ import top.wms.admin.controller.weighManage.ah.ScaleWebSocketHandler;
@Configuration
@EnableWebSocket
public class webSocket implements WebSocketConfigurer {
public class WebSocketConfig implements WebSocketConfigurer {
@Autowired
private CameraWebSocketHandler cameraWebSocketHandler;
@@ -19,7 +19,7 @@ public class webSocket implements WebSocketConfigurer {
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
// 注册WebSocket端点允许所有跨域请求
registry.addHandler(new ScaleWebSocketHandler(), "/ws/scale").setAllowedOrigins("*");
// 注册海康相机WebSocket端点
// 注册海康相机1 WebSocket端点
registry.addHandler(cameraWebSocketHandler, "/ws/camera").setAllowedOrigins("*");
}
}

View File

@@ -76,8 +76,6 @@ public class CameraService {
if (null == stDeviceInfo) {
continue;
}
log.info("[camera {}}", i++);
printDeviceInfo(stDeviceInfo);
}
// 默认选择第一个设备
@@ -110,6 +108,15 @@ public class CameraService {
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");
return true;
} catch (Exception e) {
@@ -140,7 +147,6 @@ public class CameraService {
int nRet = MvCameraControl.MV_CC_RegisterImageCallBack(hCamera, new CameraImageCallBack() {
@Override
public int OnImageCallBack(byte[] bytes, MV_FRAME_OUT_INFO mv_frame_out_info) {
printFrameInfo(mv_frame_out_info);
processImage(bytes, mv_frame_out_info);
return 0;
}
@@ -226,7 +232,8 @@ public class CameraService {
/**
* 处理图像数据
* @param bytes 原始图像数据
*
* @param bytes 原始图像数据
* @param frameInfo 帧信息
*/
private void processImage(byte[] bytes, MV_FRAME_OUT_INFO frameInfo) {
@@ -242,41 +249,65 @@ public class CameraService {
}
lastFrameTime = currentTime;
// 打印帧信息,以便调试
printFrameInfo(frameInfo);
// 对于黑白相机MV-CE050-30GM数据是单通道灰度格式
// 将原始灰度数据转换为BufferedImage
BufferedImage image = new BufferedImage(frameInfo.width, frameInfo.height, BufferedImage.TYPE_BYTE_GRAY);
image.getRaster().setDataElements(0, 0, frameInfo.width, frameInfo.height, bytes);
int dataSizeForRGB = frameInfo.width * frameInfo.height * 3; // RGB每个像素3字节
byte[] pDataForRGB = new byte[dataSizeForRGB];
// 初始化像素转换参数
MV_CC_PIXEL_CONVERT_PARAM_EX stConvertParam = new MV_CC_PIXEL_CONVERT_PARAM_EX();
// 使用实际的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格式
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(image, "jpeg", baos);
byte[] compressedData = baos.toByteArray();
baos.close();
log.debug("Original size: {} bytes, Compressed size: {} bytes, Compression ratio: {:.2f}%",
bytes.length, compressedData.length, (1 - (double)compressedData.length / bytes.length) * 100);
log.debug("Original size: {} bytes, Converted size: {} bytes, Compressed size: {} bytes, Compression ratio: {:.2f}%",
bytes.length, pDataForRGB.length, compressedData.length, (1 - (double) compressedData.length / bytes.length) * 100);
// 创建包含图像尺寸信息和压缩数据的消息
// 消息格式: [width(4 bytes)][height(4 bytes)][image data]
byte[] message = new byte[8 + compressedData.length];
// 写入宽度和高度(使用小端序)
message[0] = (byte) (frameInfo.width & 0xFF);
message[1] = (byte) ((frameInfo.width >> 8) & 0xFF);
message[2] = (byte) ((frameInfo.width >> 16) & 0xFF);
message[3] = (byte) ((frameInfo.width >> 24) & 0xFF);
message[4] = (byte) (frameInfo.height & 0xFF);
message[5] = (byte) ((frameInfo.height >> 8) & 0xFF);
message[6] = (byte) ((frameInfo.height >> 16) & 0xFF);
message[7] = (byte) ((frameInfo.height >> 24) & 0xFF);
// 写入压缩后的图像数据
System.arraycopy(compressedData, 0, message, 8, compressedData.length);
// 发送图像数据到所有连接的WebSocket客户端
for (WebSocketSession session : webSocketSessions.values()) {
if (session.isOpen()) {
@@ -346,59 +377,4 @@ public class CameraService {
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());
}
}

View File

@@ -140,36 +140,20 @@ public class ConvertPixelType
// Choose a device to operate
int camIndex = -1;
while (true)
{
System.out.print("Please input camera index:");
if (scanner.hasNextInt())
{
try
{
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) + " )");
}
while (true) {
try {
camIndex = 0;
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)
{
System.out.println("Input not number.");
camIndex = -1;
break;
}
}
else
{
camIndex = -1;
} catch (Exception e) {
System.out.println("Input not number.");
camIndex = -1;
break;
}
}
}
if (-1 == camIndex) {
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);
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
byte[] pDataForRGB = new byte[dataSizeForRGB];