| 1 | package kaka.cakelight; |
| 2 | |
| 3 | import org.opencv.core.CvType; |
| 4 | import org.opencv.core.Mat; |
| 5 | import org.opencv.core.Size; |
| 6 | import org.opencv.imgproc.Imgproc; |
| 7 | |
| 8 | import java.awt.*; |
| 9 | |
| 10 | import static kaka.cakelight.Main.saveFile; |
| 11 | import static kaka.cakelight.Main.timeIt; |
| 12 | |
| 13 | public class Frame { |
| 14 | private byte[] data; |
| 15 | private Configuration config; |
| 16 | private Mat colImage; |
| 17 | private Mat rowImage; |
| 18 | |
| 19 | private Frame(byte[] data) { |
| 20 | this.data = data; |
| 21 | } |
| 22 | |
| 23 | public static Frame of(byte[] data, Configuration config) { |
| 24 | Frame frame = new Frame(data); |
| 25 | frame.config = config; |
| 26 | frame.convert(); |
| 27 | return frame; |
| 28 | } |
| 29 | |
| 30 | private void convert() { |
| 31 | /* TODO: how to do this? |
| 32 | 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. |
| 33 | 2) Resize to 16x9 and use 2 pixels of depth (or maybe 3) and interpolate for each led. |
| 34 | 3) Resize to 2 images where each led uses 2 pixels: |
| 35 | vertical - 16 x <#leds> |
| 36 | horizontal - <#leds> x 9 |
| 37 | */ |
| 38 | Mat src = new Mat(config.video.height, config.video.width, CvType.CV_8UC2); // 8-bit, unsigned, 2 channels |
| 39 | src.put(0, 0, data); |
| 40 | |
| 41 | // Mat converted = new Mat(); |
| 42 | // Mat resized = new Mat(); |
| 43 | // |
| 44 | // timeIt("total", () -> { |
| 45 | // timeIt("yuyv2rgb", () -> Imgproc.cvtColor(src, converted, Imgproc.COLOR_YUV2RGB_YUYV)); // 3.5 - 4.0 ms |
| 46 | // 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) |
| 47 | // }); |
| 48 | |
| 49 | Mat converted = new Mat(); |
| 50 | Imgproc.cvtColor(src, converted, Imgproc.COLOR_YUV2RGB_YUYV); |
| 51 | timeIt("model 1", () -> model1(converted, Imgproc.INTER_AREA)); |
| 52 | timeIt("model 2", () -> model2(converted, Imgproc.INTER_AREA)); |
| 53 | timeIt("model 3", () -> model3(converted, Imgproc.INTER_AREA)); |
| 54 | // save(converted, "/home/kaka/test-converted.data"); |
| 55 | // save(resized, "/home/kaka/test-resized.data"); |
| 56 | System.out.println("color: " + getPixel(ListPosition.BOTTOM, 0)); |
| 57 | } |
| 58 | |
| 59 | private void model1(Mat src, int interpolation) { |
| 60 | Mat resized = new Mat(); |
| 61 | Imgproc.resize(src, resized, new Size(config.leds.cols, config.leds.rows), 0, 0, interpolation); |
| 62 | } |
| 63 | |
| 64 | private void model2(Mat src, int interpolation) { |
| 65 | Mat resized = new Mat(); |
| 66 | Imgproc.resize(src, resized, new Size(16, 9), 0, 0, interpolation); |
| 67 | } |
| 68 | |
| 69 | private void model3(Mat src, int interpolation) { |
| 70 | colImage = new Mat(); |
| 71 | rowImage = new Mat(); |
| 72 | Imgproc.resize(src, colImage, new Size(config.leds.cols, 9), 0, 0, interpolation); |
| 73 | Imgproc.resize(src, rowImage, new Size(16, config.leds.rows), 0, 0, interpolation); |
| 74 | } |
| 75 | |
| 76 | public Color getPixel(ListPosition listPosition, int xy) { |
| 77 | switch (listPosition) { |
| 78 | case LEFT: |
| 79 | return pixelToColor(rowImage, 0, xy); |
| 80 | case RIGHT: |
| 81 | return pixelToColor(rowImage, config.leds.cols - 1, xy); |
| 82 | case TOP: |
| 83 | return pixelToColor(colImage, xy, 0); |
| 84 | case BOTTOM: |
| 85 | return pixelToColor(colImage, xy, config.leds.cols - 1); |
| 86 | } |
| 87 | return null; |
| 88 | } |
| 89 | |
| 90 | private Color pixelToColor(Mat image, int x, int y) { |
| 91 | byte[] rgb = new byte[3]; |
| 92 | image.get(y, x, rgb); |
| 93 | System.out.println("r = " + rgb[0] + ", g = " + rgb[1] + ", b = " + rgb[2]); |
| 94 | return new Color(rgb[0], rgb[1], rgb[2]); |
| 95 | } |
| 96 | |
| 97 | private void save(Mat mat, String filepath) { |
| 98 | byte[] data = new byte[mat.cols() * mat.rows() * mat.channels()]; |
| 99 | mat.get(0, 0, data); |
| 100 | saveFile(data, filepath); |
| 101 | } |
| 102 | |
| 103 | public byte[] getData() { |
| 104 | return data; |
| 105 | } |
| 106 | } |