gpt4 book ai didi

Java 渲染网络摄像头图像占用过多 CPU

转载 作者:太空宇宙 更新时间:2023-11-04 06:24:46 35 4
gpt4 key购买 nike

我正在编写一个连接和流式传输网络摄像头视频的应用程序。为此,我使用 Sarxos 网络摄像头库(链接 here )来获取默认网络摄像头,然后使用 WebcamPanel绘制图像。当我将应用程序交付给客户时,问题出现了,他们在一台旧机器上进行了测试,并提示该应用程序占用了太多 CPU。

我以前从未注意到这一点,当我再次测试时,令我惊讶的是,该应用程序占用了大约 33% 的 CPU,这对于一个仅连接网络摄像头并以 30 FPS 绘制图像的简单应用程序来说太多了。这是我的编程环境:Windows 7 64位,CoreI5-4460 CPU(3.2-3.4Ghz),Zotac Geforce GTX 650 Ti,Java 7u45。

我测试过,哪个部分占用了最多的CPU,那就是渲染。如果我只获取网络摄像头图像而不绘制它们,则 CPU 占用 6-7%,但当我渲染它们时,CPU 会跃升至 30-33%。我查看了WebcamPanel类看看他们是否有问题,但到目前为止我什么也没发现。绘制方法如下:

    @Override
public void paintImage(WebcamPanel owner, BufferedImage image, Graphics2D g2) {

assert owner != null;
assert image != null;
assert g2 != null;

int pw = getWidth();
int ph = getHeight();
int iw = image.getWidth();
int ih = image.getHeight();

Object antialiasing = g2.getRenderingHint(KEY_ANTIALIASING);
Object rendering = g2.getRenderingHint(KEY_RENDERING);

g2.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_OFF);
g2.setRenderingHint(KEY_RENDERING, VALUE_RENDER_SPEED);
g2.setBackground(Color.BLACK);
g2.setColor(Color.BLACK);
g2.fillRect(0, 0, pw, ph);

// resized image position and size
int x = 0;
int y = 0;
int w = 0;
int h = 0;

switch (drawMode) {
case NONE:
w = image.getWidth();
h = image.getHeight();
break;
case FILL:
w = pw;
h = ph;
break;
case FIT:
double s = Math.max((double) iw / pw, (double) ih / ph);
double niw = iw / s;
double nih = ih / s;
double dx = (pw - niw) / 2;
double dy = (ph - nih) / 2;
w = (int) niw;
h = (int) nih;
x = (int) dx;
y = (int) dy;
break;
}

if (resizedImage != null) {
resizedImage.flush();
}

if (w == image.getWidth() && h == image.getHeight() && !mirrored) {
resizedImage = image;
} else {

GraphicsEnvironment genv = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsConfiguration gc = genv.getDefaultScreenDevice().getDefaultConfiguration();

Graphics2D gr = null;
try {

resizedImage = gc.createCompatibleImage(pw, ph);
gr = resizedImage.createGraphics();
gr.setComposite(AlphaComposite.Src);

for (Map.Entry<RenderingHints.Key, Object> hint : imageRenderingHints.entrySet()) {
gr.setRenderingHint(hint.getKey(), hint.getValue());
}

gr.setBackground(Color.BLACK);
gr.setColor(Color.BLACK);
gr.fillRect(0, 0, pw, ph);

int sx1, sx2, sy1, sy2; // source rectangle coordinates
int dx1, dx2, dy1, dy2; // destination rectangle coordinates

dx1 = x;
dy1 = y;
dx2 = x + w;
dy2 = y + h;

if (mirrored) {
sx1 = iw;
sy1 = 0;
sx2 = 0;
sy2 = ih;
} else {
sx1 = 0;
sy1 = 0;
sx2 = iw;
sy2 = ih;
}

gr.drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null);

} finally {
if (gr != null) {
gr.dispose();
}
}
}

g2.drawImage(resizedImage, 0, 0, null);

if (isFPSDisplayed()) {

String str = String.format("FPS: %.1f", webcam.getFPS());

int sx = 5;
int sy = ph - 5;

g2.setFont(getFont());
g2.setColor(Color.BLACK);
g2.drawString(str, sx + 1, sy + 1);
g2.setColor(Color.WHITE);
g2.drawString(str, sx, sy);
}

if (isImageSizeDisplayed()) {

String res = String.format("%d\u2A2F%d px", iw, ih);

FontMetrics metrics = g2.getFontMetrics(getFont());
int sw = metrics.stringWidth(res);
int sx = pw - sw - 5;
int sy = ph - 5;

g2.setFont(getFont());
g2.setColor(Color.BLACK);
g2.drawString(res, sx + 1, sy + 1);
g2.setColor(Color.WHITE);
g2.drawString(res, sx, sy);
}

if (isDisplayDebugInfo()) {

if (lastRepaintTime < 0) {
lastRepaintTime = System.currentTimeMillis();
} else {

long now = System.currentTimeMillis();
String res = String.format("DEBUG: repaints per second: %.1f", (double) 1000 / (now - lastRepaintTime));
lastRepaintTime = now;
g2.setFont(getFont());
g2.setColor(Color.BLACK);
g2.drawString(res, 6, 16);
g2.setColor(Color.WHITE);
g2.drawString(res, 5, 15);
}
}

g2.setRenderingHint(KEY_ANTIALIASING, antialiasing);
g2.setRenderingHint(KEY_RENDERING, rendering);
}

我已经尝试了很多方法来优化我的渲染,但没有任何效果。我尝试过的事情:

  1. 创建兼容的缓冲图像来渲染 => 如您所见,代码中已完成。
  2. 使用 DoubleBuffer 策略 => 据我所知,该技术已在 paintComponent() 方法中完成。我还尝试使用答案 here 中的代码来实现它,但也没有结果。
  3. 打开、关闭 OpenGL,强制 DirectDraw 使用 VM 参数。没有结果。

我正在考虑更改为OpenGL库来渲染图像,但这将是最后的选择,因为我对OpenGL一无所知,而且我认为Java2D对于我的应用程序来说已经足够了。谁能帮我解决这个问题吗?

最佳答案

经过各种测试,包括使用 OpenGL 渲染网络摄像头的图像(因为我必须从头开始学习 OpenGL,所以花了我太多时间),我找到了解决方案。这些是我所做的事情:

  1. 使用OpenImja驱动程序而不是默认驱动程序。我使用 Maven 构建了 OpenImja,之后我将 4 个 jar 文件放入库路径:core-1.1.jarcore-image-1.1.jarcore-video-1.1.jarcore-video-capture-1.1.jar
  2. 规模化是行不通的。在之前的版本中,我使用了网络摄像头的最佳分辨率,并将其缩放以适合屏幕尺寸。大错误。
  3. 通过 -Dsun.java2d.noddraw=false 强制应用使用 DirectDraw 进行渲染。根据 Oracle 的说法,Swing 使用 DirectDraw 和 GDI 管道的混合来进行渲染。但由于我为 Window 编写了应用程序,所以最好只使用 DirectDraw。对于 Linux 等其他平台,也许 X11 或 OpenGL 会更好。

之后,我的应用程序的 CPU 百分比从 33% 下降到 11%。希望这会有人和我遇到同样问题的人。

关于Java 渲染网络摄像头图像占用过多 CPU,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26941876/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com