X-Git-Url: http://dolda2000.com/gitweb/?a=blobdiff_plain;f=src%2Fkaka%2Fcakelight%2FFrame.java;h=053b7137337c62bac1c0ff91d8140e7a60f89b04;hb=b3e103128bae11de70b5ca0bbf9255953d008eaf;hp=0031abca50161b9e78a13f717fba545f83d0a684;hpb=e59e98fcf77a104e31dd97641b0ceea6d0a79e00;p=kaka%2Fcakelight.git diff --git a/src/kaka/cakelight/Frame.java b/src/kaka/cakelight/Frame.java index 0031abc..053b713 100644 --- a/src/kaka/cakelight/Frame.java +++ b/src/kaka/cakelight/Frame.java @@ -11,6 +11,10 @@ import static kaka.cakelight.Main.timeIt; public class Frame { private byte[] data; private Configuration config; +// private Mat colImage; +// private Mat rowImage; + private Mat converted; + private Mat[] images; private Frame(byte[] data) { this.data = data; @@ -24,18 +28,118 @@ public class Frame { } private void convert() { + /* TODO: how to do this? + 1) Resize to an image with the size of the number of leds and use config to define how many pixels deep into the screen to use. + 2) Resize to 16x9 and use 2 pixels of depth (or maybe 3) and interpolate for each led. + 3) Resize to 2 images where each led uses 2 pixels: + vertical - 16 x <#leds> + horizontal - <#leds> x 9 + 4) Resize to cols x rows first, then resize to a vertical and a horizontal like in (3). + */ Mat src = new Mat(config.video.height, config.video.width, CvType.CV_8UC2); // 8-bit, unsigned, 2 channels src.put(0, 0, data); - Mat converted = new Mat(); - Mat resized = new Mat(); +// Mat converted = new Mat(); +// Mat resized = new Mat(); +// +// timeIt("total", () -> { +// timeIt("yuyv2rgb", () -> Imgproc.cvtColor(src, converted, Imgproc.COLOR_YUV2RGB_YUYV)); // 3.5 - 4.0 ms +// timeIt("resizing", () -> Imgproc.resize(converted, resized, new Size(config.leds.cols, config.leds.rows), 0, 0, Imgproc.INTER_AREA)); // INTER_AREA is the best for shrinking, but also the slowest (~1.5 ms) +// }); - timeIt("total", () -> { - timeIt("yuyv2rgb", () -> Imgproc.cvtColor(src, converted, Imgproc.COLOR_YUV2RGB_YUYV)); // 3.5 - 4.0 ms - timeIt("resizing", () -> Imgproc.resize(converted, resized, new Size(config.leds.cols, config.leds.rows), 0, 0, Imgproc.INTER_AREA)); // INTER_AREA is the best for shrinking, but also the slowest (~1.5 ms) - }); + Mat cropped = src.submat( + config.video.crop.top, + config.video.height - config.video.crop.bottom, + config.video.crop.left, + config.video.width - config.video.crop.right + ); + converted = new Mat(); + Imgproc.cvtColor(cropped, converted, config.video.format); +// timeIt("model 1", () -> model1(converted, Imgproc.INTER_AREA)); +// timeIt("model 2", () -> model2(converted, Imgproc.INTER_AREA)); +// timeIt("model 3", () -> model3(converted, Imgproc.INTER_AREA)); + timeIt("model 4", () -> model4(converted, Imgproc.INTER_AREA)); // save(converted, "/home/kaka/test-converted.data"); // save(resized, "/home/kaka/test-resized.data"); + src.release(); + cropped.release(); + } + + private void model1(Mat src, int interpolation) { + Mat resized = new Mat(); + Imgproc.resize(src, resized, new Size(config.leds.cols, config.leds.rows), 0, 0, interpolation); + } + + private void model2(Mat src, int interpolation) { + Mat resized = new Mat(); + Imgproc.resize(src, resized, new Size(16, 9), 0, 0, interpolation); + } + + private void model3(Mat src, int interpolation) { +// colImage = new Mat(); +// rowImage = new Mat(); +// Imgproc.resize(src, colImage, new Size(config.leds.cols, 9), 0, 0, interpolation); +// Imgproc.resize(src, rowImage, new Size(16, config.leds.rows), 0, 0, interpolation); + } + + private void model4(Mat src, int interpolation) { + int width = 3 * src.cols() / 16; + int height = 3 * src.rows() / 9; + Mat[] cropped = new Mat[] { + /* LEFT */ src.submat(0, src.rows(), 0, width), + /* RIGHT */ src.submat(0, src.rows(), src.cols() - width, src.cols()), + /* TOP */ src.submat(0, height, 0, src.cols()), + /* BOTTOM */ src.submat(src.rows() - height, src.rows(), 0, src.cols()), + }; + images = new Mat[] {new Mat(), new Mat(), new Mat(), new Mat()}; +// Imgproc.resize(cropped[ListPosition.LEFT.ordinal()], images[ListPosition.LEFT.ordinal()], new Size(3, config.leds.rows), 0, 0, interpolation); + Imgproc.resize(cropped[0], images[0], new Size(3, config.leds.rows), 0, 0, interpolation); + Imgproc.resize(cropped[1], images[1], new Size(3, config.leds.rows), 0, 0, interpolation); + Imgproc.resize(cropped[2], images[2], new Size(config.leds.cols, 3), 0, 0, interpolation); + Imgproc.resize(cropped[3], images[3], new Size(config.leds.cols, 3), 0, 0, interpolation); +// Imgproc.resize(src, colImage, new Size(config.leds.cols, 9), 0, 0, interpolation); +// Imgproc.resize(src, rowImage, new Size(16, config.leds.rows), 0, 0, interpolation); + } + + private Color wrappedGetLedColor(ListPosition listPosition, int xy) { + Color c = getLedColor(listPosition, xy); + double[] hsv = c.toHSV(); + return Color.hsv(hsv[0], 1, 1); + } + + private Color getLedColor(ListPosition listPosition, int xy) { + // TODO: maybe use highest value from pixels? 100 % from 1st, 66 % from 2nd, 33 % from 3rd. colors might be strange. + switch (listPosition) { + case LEFT: + return interpolatedRowColor(images[0], xy, 0, 1, 2); +// return interpolatedRowColor(xy, 0, 1, 2); + case RIGHT: + return interpolatedRowColor(images[1], xy, 2, 1, 0); +// return interpolatedRowColor(xy, 15, 14, 13); + case TOP: + return interpolatedColColor(images[2], xy, 0, 1, 2); +// return interpolatedColColor(xy, 0, 1, 2); + case BOTTOM: + return interpolatedColColor(images[3], xy, 2, 1, 0); +// return interpolatedColColor(xy, 8, 7, 6); + } + return null; + } + + // private Color interpolatedRowColor(int y, int x1, int x2, int x3) { + private Color interpolatedRowColor(Mat rowImage, int y, int x1, int x2, int x3) { + return pixelToColor(rowImage, x3, y).interpolate(pixelToColor(rowImage, x2, y), 0.65).interpolate(pixelToColor(rowImage, x1, y), 0.65); + } + +// private Color interpolatedColColor(int x, int y1, int y2, int y3) { + private Color interpolatedColColor(Mat colImage, int x, int y1, int y2, int y3) { + return pixelToColor(colImage, x, y3).interpolate(pixelToColor(colImage, x, y2), 0.65).interpolate(pixelToColor(colImage, x, y1), 0.65); + } + + private Color pixelToColor(Mat image, int x, int y) { + byte[] rgb = new byte[3]; + image.get(y, x, rgb); + return Color.rgb(rgb[0] & 0xff, rgb[1] & 0xff, rgb[2] & 0xff); } private void save(Mat mat, String filepath) { @@ -45,6 +149,33 @@ public class Frame { } public byte[] getData() { - return data; + byte[] buff = new byte[(int) (converted.total() * converted.channels())]; + converted.get(0, 0, buff); + return buff; + } + +// public Mat getColImage() { +// return colImage; +// } + +// public Mat getRowImage() { +// return rowImage; +// } + + public Mat getConvertedImage() { + return converted; + } + + /** + * Creates a LED frame going counter-clockwise from the bottom-left corner, sans the corners. + */ + public LedFrame getLedFrame() { + LedFrame frame = LedFrame.from(config); + int led = 0; + for (int i = 0; i < config.leds.cols; i++) frame.setLedColor(led++, wrappedGetLedColor(ListPosition.BOTTOM, i)); + for (int i = config.leds.rows - 1; i >= 0; i--) frame.setLedColor(led++, wrappedGetLedColor(ListPosition.RIGHT, i)); + for (int i = config.leds.cols - 1; i >= 0; i--) frame.setLedColor(led++, wrappedGetLedColor(ListPosition.TOP, i)); + for (int i = 0; i < config.leds.rows; i++) frame.setLedColor(led++, wrappedGetLedColor(ListPosition.LEFT, i)); + return frame; } }