先看效果
这是微软相机,22ms延迟 (不走网络存粹寄存器和内存的通信)这是程序抓取摄像头然后传给client,client的java窗口展示的,延时也是22ms(对了localhost好像也不走网络吧)
几个点
1.opencv如何引用
2. .proto
3. stub选择
opencv引用
opencv是平台相关的,毕竟他要访问硬件,借助操作系统。所以maven gradle这种东西就不太支持这样的组件,windows下的直接用opencv开发的例子可以找很多
下面是一个
https://blog.csdn.net/qq_37131111/article/details/126588443
但我找到了一个更好用的。可以更轻松的平台迁移(只需要把.dll 或者.so 放到javahome/bin下就可以)。
https://github.com/openpnp/opencv
gradle引用
dependencies {
//不知道为什么在最外层的build.gradle里加就不可以
implementation('org.openpnp:opencv:4.5.1-2') (90MB下很长时间 ,连英国很快)
}
下载dll
org.openpnp:opencv:4.5.1-2,需要的是opencv_java451.dll ,即opencv 4.5.1版本。
https://opencv.org/releases/page/2/
.dll放到 javahome/bin下
代码里使用
server里
启动的时候加载
@SpringBootApplication
public class LocalGrpcServerApplication {
static {
System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME);
//add opencv_java451.dll to C:\Program Files\Java\jdk-17.0.2\bin
}
public static void main(String[] args) {
SpringApplication.run(LocalGrpcServerApplication.class, args);
}
}
int camId = request.getCameraId();
VideoCapture cap = null;
try {
System.out.println("-----z--1----" + camId);
cap = new VideoCapture(camId);
//} catch (Exception e) {
} catch (Throwable e) {
System.out.println("-----------");
// e.printStackTrace();
e.getMessage();
}
Mat frame = new Mat();
MatOfByte buf = new MatOfByte();
while (cap.grab()) {
Date date = new Date();
cap.read(frame);
Imgcodecs.imencode(".png", frame, buf);
CameraStreamResponse response =
CameraStreamResponse.newBuilder()
.setFrame(ByteString.copyFrom(buf.toArray()))
//.setFrame(buf.toArray())
.setTimestamp(date.getTime())
.build();
responseObserver.onNext(response);
}
cap.release();
responseObserver.onCompleted();
client
@SpringBootApplication
public class LocalGrpcClientApplication {
public static void main(String[] args) {
// SpringApplication.run(LocalGrpcClientApplication.class, args);
// 用有头模式启动, 才可以有java窗口
SpringApplicationBuilder builder = new SpringApplicationBuilder(LocalGrpcClientApplication.class);
builder.headless(false).run(args);
}
}
public void cameraStream(int camId) {
CameraStreamRequest cameraStreamRequest = CameraStreamRequest.newBuilder().setCameraId(camId).build();
Iterator<CameraStreamResponse> cameraStreamResponses = cameraStreamBlockingStub.cameraStream(cameraStreamRequest);
JFrame window = null;
try {
window = new JFrame();
} catch (HeadlessException e) {
e.printStackTrace();
}
JLabel screen = new JLabel();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
ImageIcon ic = null;
try {
ic = new ImageIcon(ImageIO.read(new File("C:\\Users\\king\\IdeaProjects\\grpc-spring\\examples\\local-grpc-client\\src\\main\\java\\net\\devh\\boot\\grpc\\examples\\local\\client\\loadImage.png")));
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
screen.setIcon(ic);
window.setContentPane(screen);
window.pack();
int i = 99;
while(cameraStreamResponses.hasNext()) {
i++;
CameraStreamResponse response = cameraStreamResponses.next();
ic = new ImageIcon(response.getFrame().toByteArray());
screen.setIcon(ic);
window.setContentPane(screen);
window.pack();
if (i % 100 == 0) {
System.out.println(response.getTimestamp() );
}
}
window.dispatchEvent(new WindowEvent(window, WindowEvent.WINDOW_CLOSED));
}
这里注意
使用的是cameraStreamBlockingStub
也可以使用 cameraStreamStub
一个同步一个异步。后者是操作见上个文章里的server steaming里的client端
用哪个以后看效果。
哦 .proto
// Camera stream service definition
service CameraStream {
// Method to connect and start receiving camera frames
rpc CameraStream(CameraStreamRequest) returns (stream CameraStreamResponse) {}
}
// camera id
message CameraStreamRequest {
int32 cameraId = 1;
}
// Camera frame message
// 帧编码压缩, client 缓冲接收 //也许可以不压缩 (现在是1.5G的光纤,配上超六类网线也许可以不压缩) //使用模拟摄像头软件(不,有摄像头)
message CameraStreamResponse {
bytes frame = 1;
int64 timestamp = 2;
}