1 package kaka.cakelight;
3 import org.opencv.core.CvType;
4 import org.opencv.core.Mat;
5 import org.opencv.core.Size;
6 import org.opencv.imgproc.Imgproc;
8 import static kaka.cakelight.Main.saveFile;
9 import static kaka.cakelight.Main.timeIt;
11 public class VideoFrame {
13 private Configuration config;
14 // private Mat colImage;
15 // private Mat rowImage;
16 private Mat converted;
19 private VideoFrame(byte[] data) {
23 public static VideoFrame of(byte[] data, Configuration config) {
24 VideoFrame frame = new VideoFrame(data);
25 frame.config = config;
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 4) Resize to cols x rows first, then resize to a vertical and a horizontal like in (3).
39 Mat src = new Mat(config.video.height, config.video.width, CvType.CV_8UC2); // 8-bit, unsigned, 2 channels
42 // Mat converted = new Mat();
43 // Mat resized = new Mat();
45 // timeIt("total", () -> {
46 // timeIt("yuyv2rgb", () -> Imgproc.cvtColor(src, converted, Imgproc.COLOR_YUV2RGB_YUYV)); // 3.5 - 4.0 ms
47 // 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)
50 Mat cropped = src.submat(
51 config.video.crop.top,
52 config.video.height - config.video.crop.bottom,
53 config.video.crop.left,
54 config.video.width - config.video.crop.right
56 converted = new Mat();
57 Imgproc.cvtColor(cropped, converted, config.video.format);
58 // timeIt("model 1", () -> model1(converted, Imgproc.INTER_AREA));
59 // timeIt("model 2", () -> model2(converted, Imgproc.INTER_AREA));
60 // timeIt("model 3", () -> model3(converted, Imgproc.INTER_AREA));
61 timeIt("model 4", () -> model4(converted, Imgproc.INTER_AREA));
62 // save(converted, "/home/kaka/test-converted.data");
63 // save(resized, "/home/kaka/test-resized.data");
68 private void model1(Mat src, int interpolation) {
69 Mat resized = new Mat();
70 Imgproc.resize(src, resized, new Size(config.leds.cols, config.leds.rows), 0, 0, interpolation);
73 private void model2(Mat src, int interpolation) {
74 Mat resized = new Mat();
75 Imgproc.resize(src, resized, new Size(16, 9), 0, 0, interpolation);
78 private void model3(Mat src, int interpolation) {
79 // colImage = new Mat();
80 // rowImage = new Mat();
81 // Imgproc.resize(src, colImage, new Size(config.leds.cols, 9), 0, 0, interpolation);
82 // Imgproc.resize(src, rowImage, new Size(16, config.leds.rows), 0, 0, interpolation);
85 private void model4(Mat src, int interpolation) {
86 int width = 3 * src.cols() / 16;
87 int height = 3 * src.rows() / 9;
88 Mat[] cropped = new Mat[] {
89 /* LEFT */ src.submat(0, src.rows(), 0, width),
90 /* RIGHT */ src.submat(0, src.rows(), src.cols() - width, src.cols()),
91 /* TOP */ src.submat(0, height, 0, src.cols()),
92 /* BOTTOM */ src.submat(src.rows() - height, src.rows(), 0, src.cols()),
94 images = new Mat[] {new Mat(), new Mat(), new Mat(), new Mat()};
95 // Imgproc.resize(cropped[ListPosition.LEFT.ordinal()], images[ListPosition.LEFT.ordinal()], new Size(3, config.leds.rows), 0, 0, interpolation);
96 Imgproc.resize(cropped[0], images[0], new Size(3, config.leds.rows), 0, 0, interpolation);
97 Imgproc.resize(cropped[1], images[1], new Size(3, config.leds.rows), 0, 0, interpolation);
98 Imgproc.resize(cropped[2], images[2], new Size(config.leds.cols, 3), 0, 0, interpolation);
99 Imgproc.resize(cropped[3], images[3], new Size(config.leds.cols, 3), 0, 0, interpolation);
100 // Imgproc.resize(src, colImage, new Size(config.leds.cols, 9), 0, 0, interpolation);
101 // Imgproc.resize(src, rowImage, new Size(16, config.leds.rows), 0, 0, interpolation);
104 private Color wrappedGetLedColor(ListPosition listPosition, int xy) {
105 Color c = getLedColor(listPosition, xy);
106 double[] hsv = c.toHSV();
107 return Color.hsv(hsv[0], 1, 1);
110 private Color getLedColor(ListPosition listPosition, int xy) {
111 // TODO: maybe use highest value from pixels? 100 % from 1st, 66 % from 2nd, 33 % from 3rd. colors might be strange.
112 switch (listPosition) {
114 return interpolatedRowColor(images[0], xy, 0, 1, 2);
115 // return interpolatedRowColor(xy, 0, 1, 2);
117 return interpolatedRowColor(images[1], xy, 2, 1, 0);
118 // return interpolatedRowColor(xy, 15, 14, 13);
120 return interpolatedColColor(images[2], xy, 0, 1, 2);
121 // return interpolatedColColor(xy, 0, 1, 2);
123 return interpolatedColColor(images[3], xy, 2, 1, 0);
124 // return interpolatedColColor(xy, 8, 7, 6);
129 // private Color interpolatedRowColor(int y, int x1, int x2, int x3) {
130 private Color interpolatedRowColor(Mat rowImage, int y, int x1, int x2, int x3) {
131 return pixelToColor(rowImage, x3, y).interpolate(pixelToColor(rowImage, x2, y), 0.65).interpolate(pixelToColor(rowImage, x1, y), 0.65);
134 // private Color interpolatedColColor(int x, int y1, int y2, int y3) {
135 private Color interpolatedColColor(Mat colImage, int x, int y1, int y2, int y3) {
136 return pixelToColor(colImage, x, y3).interpolate(pixelToColor(colImage, x, y2), 0.65).interpolate(pixelToColor(colImage, x, y1), 0.65);
139 private Color pixelToColor(Mat image, int x, int y) {
140 byte[] rgb = new byte[3];
141 image.get(y, x, rgb);
142 return Color.rgb(rgb[0] & 0xff, rgb[1] & 0xff, rgb[2] & 0xff);
145 private void save(Mat mat, String filepath) {
146 byte[] data = new byte[mat.cols() * mat.rows() * mat.channels()];
148 saveFile(data, filepath);
151 public byte[] getData() {
152 byte[] buff = new byte[(int) (converted.total() * converted.channels())];
153 converted.get(0, 0, buff);
157 // public Mat getColImage() {
161 // public Mat getRowImage() {
165 public Mat getConvertedImage() {
170 * Creates a LED frame going counter-clockwise from the bottom-left corner, sans the corners.
172 public LedFrame getLedFrame() {
173 LedFrame frame = LedFrame.from(config);
176 if (config.video.list.bottom)
177 for (int i = 0; i < config.leds.cols; i++) frame.setLedColor(led++, wrappedGetLedColor(ListPosition.BOTTOM, i));
179 for (int i = 0; i < config.leds.cols; i++) frame.setLedColor(led++, Color.BLACK);
181 if (config.video.list.right)
182 for (int i = config.leds.rows - 1; i >= 0; i--) frame.setLedColor(led++, wrappedGetLedColor(ListPosition.RIGHT, i));
184 for (int i = config.leds.rows - 1; i >= 0; i--) frame.setLedColor(led++, Color.BLACK);
186 if (config.video.list.top)
187 for (int i = config.leds.cols - 1; i >= 0; i--) frame.setLedColor(led++, wrappedGetLedColor(ListPosition.TOP, i));
189 for (int i = config.leds.cols - 1; i >= 0; i--) frame.setLedColor(led++, Color.BLACK);
191 if (config.video.list.left)
192 for (int i = 0; i < config.leds.rows; i++) frame.setLedColor(led++, wrappedGetLedColor(ListPosition.LEFT, i));
194 for (int i = 0; i < config.leds.rows; i++) frame.setLedColor(led++, Color.BLACK);