This commit is contained in:
2025-12-30 15:43:06 +01:00
commit 98a68ef75e
8 changed files with 426 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
package io.swtc.proccessing;
public class AutoGainProcessor {
public float[] calculateAutoGains(int[] pixels) {
long rSum = 0, gSum = 0, bSum = 0;
int step = 8;
int sampledCount = 0;
for (int i = 0; i < pixels.length; i += step) {
int pixel = pixels[i];
rSum += (pixel >> 16) & 0xFF;
gSum += (pixel >> 8) & 0xFF;
bSum += pixel & 0xFF;
sampledCount++;
}
if (sampledCount == 0) return new float[]{1f, 1f, 1f};
float rAvg = (float) rSum / sampledCount;
float gAvg = (float) gSum / sampledCount;
float bAvg = (float) bSum / sampledCount;
float grayAvg = (rAvg + gAvg + bAvg) / 3.0f;
if (grayAvg < 1.0f) return new float[]{1.0f, 1.0f, 1.0f};
return new float[]{
Math.min(2.0f, grayAvg / rAvg),
Math.min(2.0f, grayAvg / gAvg),
Math.min(2.0f, grayAvg / bAvg)
};
}
}

View File

@@ -0,0 +1,96 @@
package io.swtc.proccessing;
import org.eclipse.swt.opengl.GLCanvas;
import org.eclipse.swt.widgets.Composite;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL11;
import java.awt.image.BufferedImage;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class CameraRenderer {
private final GLCanvas canvas;
private int textureId = -1;
private ByteBuffer pixelBuffer;
private final AutoGainProcessor gainProcessor;
public CameraRenderer(Composite parent, org.eclipse.swt.opengl.GLData data) {
this.canvas = new GLCanvas(parent, 0, data);
this.gainProcessor = new AutoGainProcessor();
// Initialize OpenGL context immediately
this.canvas.setCurrent();
GL.createCapabilities();
initGL();
}
public GLCanvas getCanvas() {
return canvas;
}
private void initGL() {
GL11.glEnable(GL11.GL_TEXTURE_2D);
textureId = GL11.glGenTextures();
}
public void render(BufferedImage img) {
if (canvas.isDisposed()) return;
canvas.setCurrent();
int width = img.getWidth();
int height = img.getHeight();
int[] rgbArray = new int[width * height];
// this is hellishly unefficcient but who cares.
img.getRGB(0, 0, width, height, rgbArray, 0, width);
float[] gains = gainProcessor.calculateAutoGains(rgbArray);
int bufferSize = width * height * 3;
if (pixelBuffer == null || pixelBuffer.capacity() < bufferSize) {
pixelBuffer = ByteBuffer.allocateDirect(bufferSize);
pixelBuffer.order(ByteOrder.nativeOrder());
}
pixelBuffer.clear();
for (int pixel : rgbArray) {
int r = (pixel >> 16) & 0xFF;
int g = (pixel >> 8) & 0xFF;
int b = pixel & 0xFF;
r = Math.min(255, (int)(r * gains[0]));
g = Math.min(255, (int)(g * gains[1]));
b = Math.min(255, (int)(b * gains[2]));
pixelBuffer.put((byte) r);
pixelBuffer.put((byte) g);
pixelBuffer.put((byte) b);
}
pixelBuffer.flip();
// this is just gl stuff
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
GL11.glViewport(0, 0, canvas.getClientArea().width, canvas.getClientArea().height);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureId);
GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, width, height,
0, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, pixelBuffer);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
GL11.glColor3f(1.0f, 1.0f, 1.0f);
GL11.glBegin(GL11.GL_QUADS);
GL11.glTexCoord2f(0, 0); GL11.glVertex2f(-1, 1);
GL11.glTexCoord2f(1, 0); GL11.glVertex2f(1, 1);
GL11.glTexCoord2f(1, 1); GL11.glVertex2f(1, -1);
GL11.glTexCoord2f(0, 1); GL11.glVertex2f(-1, -1);
GL11.glEnd();
canvas.swapBuffers();
}
}

View File

@@ -0,0 +1,50 @@
package io.swtc.proccessing;
import com.github.sarxos.webcam.Webcam;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.util.function.Consumer;
public class WebcamCaptureLoop {
private final Webcam webcam;
private final Consumer<BufferedImage> onFrameCaptured;
private volatile boolean running = false;
public WebcamCaptureLoop(Webcam webcam, Consumer<BufferedImage> onFrameCaptured) {
this.webcam = webcam;
this.onFrameCaptured = onFrameCaptured;
// Configure webcam
Dimension[] sizes = webcam.getViewSizes();
webcam.setViewSize(sizes[sizes.length - 1]);
}
public void start() {
if (running) return;
running = true;
Thread captureThread = new Thread(() -> {
webcam.open();
while (running) {
BufferedImage img = webcam.getImage();
if (img != null) {
onFrameCaptured.accept(img);
}
try {
Thread.sleep(15);
} catch (InterruptedException e) {
break;
}
}
webcam.close();
});
captureThread.setName("cam_cap_thread");
captureThread.start();
}
public void stop() {
running = false;
}
}