From e59e98fcf77a104e31dd97641b0ceea6d0a79e00 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tomas=20Wenstr=C3=B6m?= Date: Sun, 12 Feb 2017 22:30:15 +0100 Subject: [PATCH] initial commit --- .gitignore | 3 ++ config.properties | 9 ++++ src/kaka/cakelight/Configuration.java | 81 +++++++++++++++++++++++++++++++++++ src/kaka/cakelight/Frame.java | 50 +++++++++++++++++++++ src/kaka/cakelight/FrameGrabber.java | 52 ++++++++++++++++++++++ src/kaka/cakelight/Main.java | 54 +++++++++++++++++++++++ 6 files changed, 249 insertions(+) create mode 100644 .gitignore create mode 100644 config.properties create mode 100644 src/kaka/cakelight/Configuration.java create mode 100644 src/kaka/cakelight/Frame.java create mode 100644 src/kaka/cakelight/FrameGrabber.java create mode 100644 src/kaka/cakelight/Main.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a6c1087 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea +CakeLight.iml +out diff --git a/config.properties b/config.properties new file mode 100644 index 0000000..b3f150f --- /dev/null +++ b/config.properties @@ -0,0 +1,9 @@ +# default settings + +video.device=/dev/video0 +video.width=720 +video.height=576 +video.bpp=2 + +leds.cols=32 +leds.rows=18 diff --git a/src/kaka/cakelight/Configuration.java b/src/kaka/cakelight/Configuration.java new file mode 100644 index 0000000..35fde30 --- /dev/null +++ b/src/kaka/cakelight/Configuration.java @@ -0,0 +1,81 @@ +package kaka.cakelight; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.*; +import java.util.stream.Collectors; + +public class Configuration { + private List> settings = new ArrayList<>(); + public VideoConfiguration video; + public LedConfiguration leds; + + private Configuration(Properties prop) { + video = new VideoConfiguration(prop); + leds = new LedConfiguration(prop); + } + + public static Configuration from(String propertiesFile) { + InputStream input = null; + try { + input = new FileInputStream(propertiesFile); + Properties prop = new Properties(); + prop.load(input); + return new Configuration(prop); + } catch (IOException ex) { + ex.printStackTrace(); + } finally { + if (input != null) { + try { + input.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return null; + } + + private String get(Properties prop, String name) { + return addSetting(name, prop.getProperty(name)); + } + + private String get(Properties prop, String name, String dflt) { + return addSetting(name, prop.getProperty(name, dflt)); + } + + private String addSetting(String name, String value) { + settings.add(new AbstractMap.SimpleEntry<>(name, value)); + return value; + } + + @Override + public String toString() { + return settings.stream().map(entry -> entry.getKey() + "=" + entry.getValue()).collect(Collectors.joining("\n")); + } + + public class VideoConfiguration { + public String device; + public int width; + public int height; + public int bpp; + + private VideoConfiguration(Properties prop) { + device = get(prop, "video.device", "/dev/video0"); + width = Integer.parseInt(get(prop, "video.width", "720")); + height = Integer.parseInt(get(prop, "video.height", "576")); + bpp = Integer.parseInt(get(prop, "video.bpp", "2")); + } + } + + public class LedConfiguration { + public int cols; + public int rows; + + private LedConfiguration(Properties prop) { + cols = Integer.parseInt(get(prop, "leds.cols")); + rows = Integer.parseInt(get(prop, "leds.rows")); + } + } +} diff --git a/src/kaka/cakelight/Frame.java b/src/kaka/cakelight/Frame.java new file mode 100644 index 0000000..0031abc --- /dev/null +++ b/src/kaka/cakelight/Frame.java @@ -0,0 +1,50 @@ +package kaka.cakelight; + +import org.opencv.core.CvType; +import org.opencv.core.Mat; +import org.opencv.core.Size; +import org.opencv.imgproc.Imgproc; + +import static kaka.cakelight.Main.saveFile; +import static kaka.cakelight.Main.timeIt; + +public class Frame { + private byte[] data; + private Configuration config; + + private Frame(byte[] data) { + this.data = data; + } + + public static Frame of(byte[] data, Configuration config) { + Frame frame = new Frame(data); + frame.config = config; + frame.convert(); + return frame; + } + + private void convert() { + 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(); + + 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) + }); +// save(converted, "/home/kaka/test-converted.data"); +// save(resized, "/home/kaka/test-resized.data"); + } + + private void save(Mat mat, String filepath) { + byte[] data = new byte[mat.cols() * mat.rows() * mat.channels()]; + mat.get(0, 0, data); + saveFile(data, filepath); + } + + public byte[] getData() { + return data; + } +} diff --git a/src/kaka/cakelight/FrameGrabber.java b/src/kaka/cakelight/FrameGrabber.java new file mode 100644 index 0000000..d228b7b --- /dev/null +++ b/src/kaka/cakelight/FrameGrabber.java @@ -0,0 +1,52 @@ +package kaka.cakelight; + +import java.io.*; + +public class FrameGrabber { + private Configuration config; + private File file; + private int bytesPerFrame; + private InputStream fileStream; + + private FrameGrabber() { + } + + public static FrameGrabber from(Configuration config) { + FrameGrabber fg = new FrameGrabber(); + fg.config = config; + fg.file = new File(config.video.device); + fg.bytesPerFrame = config.video.width * config.video.height * config.video.bpp; + return fg; + } + + public boolean prepare() { + try { + fileStream = new FileInputStream(file); + return true; + } catch (FileNotFoundException e) { + e.printStackTrace(); + return false; + } + } + + public Frame grabFrame() { + try { + byte[] data = new byte[bytesPerFrame]; + int count = fileStream.read(data); + System.out.println("count = " + count); + return Frame.of(data, config); + } catch (IOException e) { + e.printStackTrace(); + } + + return null; + } + + public void close() { + try { + fileStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/src/kaka/cakelight/Main.java b/src/kaka/cakelight/Main.java new file mode 100644 index 0000000..474683e --- /dev/null +++ b/src/kaka/cakelight/Main.java @@ -0,0 +1,54 @@ +package kaka.cakelight; + +import org.opencv.core.Core; + +import java.io.FileOutputStream; +import java.io.IOException; + +public class Main { + + public static void main(String[] args) { + System.loadLibrary(Core.NATIVE_LIBRARY_NAME); + + Configuration config = Configuration.from("config.properties"); + System.out.println("Running with config:\n" + config); + + FrameGrabber grabber = FrameGrabber.from(config); + grabber.prepare(); + Frame frame = grabber.grabFrame(); + double time = 0; + for (int i = 0; i < 100; i++) { + time += timeIt("frame", () -> grabber.grabFrame()); + } + System.out.println("time = " + time); + grabber.close(); +// byte[] data = frame.getData(); +// saveFile(data, "/home/kaka/test.img"); + } + + public static void saveFile(byte[] data, String filepath) { + try { + FileOutputStream fos = new FileOutputStream(filepath); + fos.write(data); + fos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static double timeIt(String tag, Runnable lambda) { + long start = System.nanoTime(); + lambda.run(); + long end = System.nanoTime(); + double duration = (end - start) * 0.000001; + System.out.println("duration (ms): " + tag + " = " + duration); + return duration; + } +} + +/* +FrameGrabber läser frames asynkront +skickar frame till FrameConverter +sparas i huvudklassen +läses av FrameProcessor/LedController + */ \ No newline at end of file -- 2.11.0