Added a custom Color class
[kaka/cakelight.git] / src / kaka / cakelight / Frame.java
CommitLineData
e59e98fc
TW
1package kaka.cakelight;
2
3import org.opencv.core.CvType;
4import org.opencv.core.Mat;
5import org.opencv.core.Size;
6import org.opencv.imgproc.Imgproc;
7
8import static kaka.cakelight.Main.saveFile;
9import static kaka.cakelight.Main.timeIt;
10
11public class Frame {
12 private byte[] data;
13 private Configuration config;
4a2d6056
TW
14 private Mat colImage;
15 private Mat rowImage;
100b82fe 16 private Mat converted;
e59e98fc
TW
17
18 private Frame(byte[] data) {
19 this.data = data;
20 }
21
22 public static Frame of(byte[] data, Configuration config) {
23 Frame frame = new Frame(data);
24 frame.config = config;
25 frame.convert();
26 return frame;
27 }
28
29 private void convert() {
4a2d6056
TW
30 /* TODO: how to do this?
31 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.
32 2) Resize to 16x9 and use 2 pixels of depth (or maybe 3) and interpolate for each led.
33 3) Resize to 2 images where each led uses 2 pixels:
34 vertical - 16 x <#leds>
35 horizontal - <#leds> x 9
cc03403a 36 4) Resize to cols x rows first, then resize to a vertical and a horizontal like in (3).
4a2d6056 37 */
e59e98fc
TW
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
4a2d6056
TW
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// });
e59e98fc 48
100b82fe
TW
49 Mat cropped = src.submat(
50 config.video.crop.top,
51 config.video.height - config.video.crop.bottom,
52 config.video.crop.left,
53 config.video.width - config.video.crop.right
54 );
55 converted = new Mat();
cc03403a 56 Imgproc.cvtColor(cropped, converted, config.video.format);
100b82fe
TW
57// timeIt("model 1", () -> model1(converted, Imgproc.INTER_AREA));
58// timeIt("model 2", () -> model2(converted, Imgproc.INTER_AREA));
4a2d6056 59 timeIt("model 3", () -> model3(converted, Imgproc.INTER_AREA));
e59e98fc
TW
60// save(converted, "/home/kaka/test-converted.data");
61// save(resized, "/home/kaka/test-resized.data");
100b82fe
TW
62 src.release();
63 cropped.release();
4a2d6056
TW
64 }
65
66 private void model1(Mat src, int interpolation) {
67 Mat resized = new Mat();
68 Imgproc.resize(src, resized, new Size(config.leds.cols, config.leds.rows), 0, 0, interpolation);
69 }
70
71 private void model2(Mat src, int interpolation) {
72 Mat resized = new Mat();
73 Imgproc.resize(src, resized, new Size(16, 9), 0, 0, interpolation);
74 }
75
76 private void model3(Mat src, int interpolation) {
77 colImage = new Mat();
78 rowImage = new Mat();
79 Imgproc.resize(src, colImage, new Size(config.leds.cols, 9), 0, 0, interpolation);
80 Imgproc.resize(src, rowImage, new Size(16, config.leds.rows), 0, 0, interpolation);
81 }
82
100b82fe 83 public Color getLedColor(ListPosition listPosition, int xy) {
cc03403a 84 // TODO: maybe use highest value from pixels? 100 % from 1st, 66 % from 2nd, 33 % from 3rd. colors might be strange.
4a2d6056
TW
85 switch (listPosition) {
86 case LEFT:
100b82fe 87 return interpolatedRowColor(xy, 0, 1, 2);
4a2d6056 88 case RIGHT:
100b82fe 89 return interpolatedRowColor(xy, 15, 14, 13);
4a2d6056 90 case TOP:
100b82fe 91 return interpolatedColColor(xy, 0, 1, 2);
4a2d6056 92 case BOTTOM:
100b82fe 93 return interpolatedColColor(xy, 8, 7, 6);
4a2d6056
TW
94 }
95 return null;
96 }
97
100b82fe
TW
98 private Color interpolatedRowColor(int y, int x1, int x2, int x3) {
99 return pixelToColor(rowImage, x3, y).interpolate(pixelToColor(rowImage, x2, y), 0.65).interpolate(pixelToColor(rowImage, x1, y), 0.65);
100 }
101
102 private Color interpolatedColColor(int x, int y1, int y2, int y3) {
103 return pixelToColor(colImage, x, y3).interpolate(pixelToColor(colImage, x, y2), 0.65).interpolate(pixelToColor(colImage, x, y1), 0.65);
104 }
105
4a2d6056
TW
106 private Color pixelToColor(Mat image, int x, int y) {
107 byte[] rgb = new byte[3];
108 image.get(y, x, rgb);
100b82fe 109 return Color.rgb(rgb[0] & 0xff, rgb[1] & 0xff, rgb[2] & 0xff);
e59e98fc
TW
110 }
111
112 private void save(Mat mat, String filepath) {
113 byte[] data = new byte[mat.cols() * mat.rows() * mat.channels()];
114 mat.get(0, 0, data);
115 saveFile(data, filepath);
116 }
117
118 public byte[] getData() {
100b82fe
TW
119 byte[] buff = new byte[(int) (converted.total() * converted.channels())];
120 converted.get(0, 0, buff);
121 return buff;
122 }
123
124 public Mat getColImage() {
125 return colImage;
126 }
127
128 public Mat getRowImage() {
129 return rowImage;
130 }
131
132 public Mat getConvertedImage() {
133 return converted;
e59e98fc 134 }
03b67a73
TW
135
136 /**
137 * Creates a LED frame going clockwise from the bottom-left corner, sans the corners.
138 */
139 public LedFrame getLedFrame() {
140 LedFrame frame = LedFrame.from(config);
141 int led = 0;
142 for (int i = config.leds.rows - 1; i >= 0; i--) frame.setLedColor(led++, getLedColor(ListPosition.LEFT, i));
143 for (int i = 0; i < config.leds.cols; i++) frame.setLedColor(led++, getLedColor(ListPosition.TOP, i));
144 for (int i = 0; i < config.leds.rows; i++) frame.setLedColor(led++, getLedColor(ListPosition.RIGHT, i));
145 for (int i = config.leds.cols - 1; i >= 0; i--) frame.setLedColor(led++, getLedColor(ListPosition.BOTTOM, i));
146 return frame;
147 }
e59e98fc 148}