-
Notifications
You must be signed in to change notification settings - Fork 109
[V2] Add operation to save image snapshots to local disk. #599
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 9 commits
d3cc497
745ec6e
2eb2d38
d5a7d9d
e40464a
625710f
aae316c
0e95afb
cfe1ffa
7a38983
5d37d7f
f48fcc6
b352d9a
411718e
532bb07
fb8590b
3365bf5
cfbe494
3dbb57c
31d56ba
2a13575
67fe91f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| package edu.wpi.grip.core; | ||
|
|
||
| public interface FileManager { | ||
| void saveImage(byte[] image, String fileName); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -48,7 +48,7 @@ public class GRIPCoreModule extends AbstractModule { | |
| globalLogger.removeHandler(handler); | ||
| } | ||
|
|
||
| final Handler fileHandler = new FileHandler("%h/GRIP.log");//Log to the file "GRIPlogger.log" | ||
| final Handler fileHandler = new FileHandler("%t/GRIP.log");//Log to the file "GRIPlogger.log" | ||
|
||
|
|
||
| //Set level to handler and logger | ||
| fileHandler.setLevel(Level.FINE); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| package edu.wpi.grip.core; | ||
|
|
||
| import com.google.common.io.Files; | ||
| import com.google.inject.Singleton; | ||
|
|
||
| import java.io.File; | ||
| import java.io.IOException; | ||
| import java.util.logging.Level; | ||
| import java.util.logging.Logger; | ||
|
|
||
| import static com.google.common.base.Preconditions.checkNotNull; | ||
|
|
||
| @Singleton | ||
| public class GripFileManager implements FileManager { | ||
|
|
||
| private static final Logger logger = Logger.getLogger(GripFileManager.class.getName()); | ||
|
|
||
| private static final File gripDirectory = new File(System.getProperty("user.home") + File.separator + "GRIP"); | ||
| private static final File imageDirectory = new File(gripDirectory, "images"); | ||
|
|
||
| public GripFileManager() { | ||
| gripDirectory.mkdirs(); | ||
| imageDirectory.mkdirs(); | ||
| } | ||
|
|
||
| @Override | ||
| public void saveImage(byte[] image, String fileName) { | ||
| checkNotNull(image); | ||
| checkNotNull(fileName); | ||
|
|
||
| File file = new File(imageDirectory, fileName); | ||
| Runnable runnable = () -> { | ||
| try { | ||
| imageDirectory.mkdirs(); // If the user deletes the directory | ||
| Files.write(image, file); | ||
| } catch (IOException ex) { | ||
| logger.log(Level.WARNING, ex.getMessage(), ex); | ||
| } | ||
| }; | ||
| new Thread(runnable).start(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package edu.wpi.grip.core; | ||
|
|
||
| import com.google.inject.AbstractModule; | ||
|
|
||
| public class GripFileModule extends AbstractModule { | ||
| @Override | ||
| protected void configure() { | ||
| bind(FileManager.class).to(GripFileManager.class); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| package edu.wpi.grip.core.operations.composite; | ||
|
|
||
| import com.google.common.base.Stopwatch; | ||
| import com.google.common.collect.ImmutableList; | ||
| import edu.wpi.grip.core.FileManager; | ||
| import edu.wpi.grip.core.Operation; | ||
| import edu.wpi.grip.core.OperationDescription; | ||
| import edu.wpi.grip.core.sockets.InputSocket; | ||
| import edu.wpi.grip.core.sockets.OutputSocket; | ||
| import edu.wpi.grip.core.sockets.SocketHint; | ||
| import edu.wpi.grip.core.sockets.SocketHints; | ||
| import edu.wpi.grip.core.util.Icon; | ||
| import org.bytedeco.javacpp.BytePointer; | ||
| import org.bytedeco.javacpp.IntPointer; | ||
|
|
||
| import java.time.LocalDateTime; | ||
| import java.time.format.DateTimeFormatter; | ||
| import java.util.List; | ||
| import java.util.concurrent.TimeUnit; | ||
|
|
||
| import static org.bytedeco.javacpp.opencv_core.Mat; | ||
| import static org.bytedeco.javacpp.opencv_imgcodecs.CV_IMWRITE_JPEG_QUALITY; | ||
| import static org.bytedeco.javacpp.opencv_imgcodecs.imencode; | ||
|
|
||
| /** | ||
| * Save JPEG files periodically to the local disk. | ||
| */ | ||
| public class SaveImageOperation implements Operation { | ||
|
|
||
| public static final OperationDescription DESCRIPTION = | ||
| OperationDescription.builder() | ||
| .name("Save Images to Disk") | ||
| .summary("Save image periodically to local disk") | ||
| .category(OperationDescription.Category.MISCELLANEOUS) | ||
| .icon(Icon.iconStream("publish-video")) | ||
| .build(); | ||
|
|
||
| private final SocketHint<Mat> inputHint = SocketHints.Inputs.createMatSocketHint("Input", false); | ||
| private final SocketHint<Number> qualityHint = SocketHints.Inputs.createNumberSliderSocketHint("Quality", 90, 0, 100); | ||
| private final SocketHint<Number> periodHint = SocketHints.Inputs.createNumberSpinnerSocketHint("Period", 0.1); | ||
| private final SocketHint<Boolean> activeHint = SocketHints.Inputs.createCheckboxSocketHint("Active", false); | ||
|
|
||
| private final SocketHint<Mat> outputHint = SocketHints.Outputs.createMatSocketHint("Output"); | ||
|
|
||
| private final InputSocket<Mat> inputSocket; | ||
| private final InputSocket<Number> qualitySocket; | ||
| private final InputSocket<Number> periodSocket; | ||
| private final InputSocket<Boolean> activeSocket; | ||
|
|
||
| private final OutputSocket<Mat> outputSocket; | ||
|
|
||
| private final FileManager fileManager; | ||
| private final BytePointer imagePointer = new BytePointer(); | ||
| private final Stopwatch stopwatch = Stopwatch.createStarted(); | ||
| private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"); | ||
|
|
||
| public SaveImageOperation(InputSocket.Factory inputSocketFactory, OutputSocket.Factory outputSocketFactory, FileManager fileManager) { | ||
| this.fileManager = fileManager; | ||
|
|
||
| inputSocket = inputSocketFactory.create(inputHint); | ||
| qualitySocket = inputSocketFactory.create(qualityHint); | ||
| periodSocket = inputSocketFactory.create(periodHint); | ||
| activeSocket = inputSocketFactory.create(activeHint); | ||
|
|
||
| outputSocket = outputSocketFactory.create(outputHint); | ||
| } | ||
|
|
||
| @Override | ||
| public List<InputSocket> getInputSockets() { | ||
| return ImmutableList.of( | ||
| inputSocket, | ||
| qualitySocket, | ||
| periodSocket, | ||
| activeSocket | ||
| ); | ||
| } | ||
|
|
||
| @Override | ||
| public List<OutputSocket> getOutputSockets() { | ||
| return ImmutableList.of( | ||
| outputSocket | ||
| ); | ||
| } | ||
|
|
||
| @Override | ||
| public void perform() { | ||
| if (!activeSocket.getValue().orElse(false)) { | ||
| return; | ||
| } | ||
|
|
||
| // don't save new image until period expires | ||
| if (stopwatch.elapsed(TimeUnit.NANOSECONDS) < periodSocket.getValue().get().doubleValue()*1000000000L) { | ||
|
||
| return; | ||
| } | ||
| stopwatch.reset(); | ||
| stopwatch.start(); | ||
|
|
||
| imencode(".jpeg", inputSocket.getValue().get(), imagePointer, new IntPointer(CV_IMWRITE_JPEG_QUALITY, | ||
| qualitySocket.getValue().get().intValue())); | ||
| byte[] buffer = new byte[128 * 1024]; | ||
| int bufferSize = imagePointer.limit(); | ||
| if (bufferSize > buffer.length) { | ||
| buffer = new byte[imagePointer.limit()]; | ||
| } | ||
| imagePointer.get(buffer, 0, bufferSize); | ||
|
|
||
| fileManager.saveImage(buffer, LocalDateTime.now().format(formatter) + ".jpeg"); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package edu.wpi.grip.core.util; | ||
|
|
||
| import edu.wpi.grip.core.FileManager; | ||
|
|
||
| public class MockFileManager implements FileManager { | ||
| @Override | ||
| public void saveImage(byte[] image, String fileName) { | ||
| // No body here because this is for testing only. | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Documentation