Try using only the hue in video mode, with max saturation and value
[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;
14d53f06
TW
14// private Mat colImage;
15// private Mat rowImage;
100b82fe 16 private Mat converted;
14d53f06 17 private Mat[] images;
e59e98fc
TW
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() {
4a2d6056
TW
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
cc03403a 37 4) Resize to cols x rows first, then resize to a vertical and a horizontal like in (3).
4a2d6056 38 */
e59e98fc
TW
39 Mat src = new Mat(config.video.height, config.video.width, CvType.CV_8UC2); // 8-bit, unsigned, 2 channels
40 src.put(0, 0, data);
41
4a2d6056
TW
42// Mat converted = new Mat();
43// Mat resized = new Mat();
44//
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)
48// });
e59e98fc 49
100b82fe
TW
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
55 );
56 converted = new Mat();
cc03403a 57 Imgproc.cvtColor(cropped, converted, config.video.format);
100b82fe
TW
58// timeIt("model 1", () -> model1(converted, Imgproc.INTER_AREA));
59// timeIt("model 2", () -> model2(converted, Imgproc.INTER_AREA));
14d53f06
TW
60// timeIt("model 3", () -> model3(converted, Imgproc.INTER_AREA));
61 timeIt("model 4", () -> model4(converted, Imgproc.INTER_AREA));
e59e98fc
TW
62// save(converted, "/home/kaka/test-converted.data");
63// save(resized, "/home/kaka/test-resized.data");
100b82fe
TW
64 src.release();
65 cropped.release();
4a2d6056
TW
66 }
67
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);
71 }
72
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);
76 }
77
78 private void model3(Mat src, int interpolation) {
14d53f06
TW
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);
83 }
84
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()),
93 };
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);
102 }
103
b3e10312
TW
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);
108 }
109
14d53f06 110 private Color getLedColor(ListPosition listPosition, int xy) {
cc03403a 111 // TODO: maybe use highest value from pixels? 100 % from 1st, 66 % from 2nd, 33 % from 3rd. colors might be strange.
4a2d6056
TW
112 switch (listPosition) {
113 case LEFT:
14d53f06
TW
114 return interpolatedRowColor(images[0], xy, 0, 1, 2);
115// return interpolatedRowColor(xy, 0, 1, 2);
4a2d6056 116 case RIGHT:
14d53f06
TW
117 return interpolatedRowColor(images[1], xy, 2, 1, 0);
118// return interpolatedRowColor(xy, 15, 14, 13);
4a2d6056 119 case TOP:
14d53f06
TW
120 return interpolatedColColor(images[2], xy, 0, 1, 2);
121// return interpolatedColColor(xy, 0, 1, 2);
4a2d6056 122 case BOTTOM:
14d53f06
TW
123 return interpolatedColColor(images[3], xy, 2, 1, 0);
124// return interpolatedColColor(xy, 8, 7, 6);
4a2d6056
TW
125 }
126 return null;
127 }
128
14d53f06
TW
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) {
100b82fe
TW
131 return pixelToColor(rowImage, x3, y).interpolate(pixelToColor(rowImage, x2, y), 0.65).interpolate(pixelToColor(rowImage, x1, y), 0.65);
132 }
133
14d53f06
TW
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) {
100b82fe
TW
136 return pixelToColor(colImage, x, y3).interpolate(pixelToColor(colImage, x, y2), 0.65).interpolate(pixelToColor(colImage, x, y1), 0.65);
137 }
138
4a2d6056
TW
139 private Color pixelToColor(Mat image, int x, int y) {
140 byte[] rgb = new byte[3];
141 image.get(y, x, rgb);
100b82fe 142 return Color.rgb(rgb[0] & 0xff, rgb[1] & 0xff, rgb[2] & 0xff);
e59e98fc
TW
143 }
144
145 private void save(Mat mat, String filepath) {
146 byte[] data = new byte[mat.cols() * mat.rows() * mat.channels()];
147 mat.get(0, 0, data);
148 saveFile(data, filepath);
149 }
150
151 public byte[] getData() {
100b82fe
TW
152 byte[] buff = new byte[(int) (converted.total() * converted.channels())];
153 converted.get(0, 0, buff);
154 return buff;
155 }
156
14d53f06
TW
157// public Mat getColImage() {
158// return colImage;
159// }
100b82fe 160
14d53f06
TW
161// public Mat getRowImage() {
162// return rowImage;
163// }
100b82fe
TW
164
165 public Mat getConvertedImage() {
166 return converted;
e59e98fc 167 }
03b67a73
TW
168
169 /**
da7bef43 170 * Creates a LED frame going counter-clockwise from the bottom-left corner, sans the corners.
03b67a73
TW
171 */
172 public LedFrame getLedFrame() {
173 LedFrame frame = LedFrame.from(config);
174 int led = 0;
b3e10312
TW
175 for (int i = 0; i < config.leds.cols; i++) frame.setLedColor(led++, wrappedGetLedColor(ListPosition.BOTTOM, i));
176 for (int i = config.leds.rows - 1; i >= 0; i--) frame.setLedColor(led++, wrappedGetLedColor(ListPosition.RIGHT, i));
177 for (int i = config.leds.cols - 1; i >= 0; i--) frame.setLedColor(led++, wrappedGetLedColor(ListPosition.TOP, i));
178 for (int i = 0; i < config.leds.rows; i++) frame.setLedColor(led++, wrappedGetLedColor(ListPosition.LEFT, i));
03b67a73
TW
179 return frame;
180 }
e59e98fc 181}