RV Image is a remote viewer for images written in Rust. You can view images, e.g., on remote SSH servers or Azure blob storages. Further, RV Image comes with a bounding box, polygon, and brush labeling tool supporting import and export of the Coco-format. So far tested on Windows 11 and Mac OS. RV Image is mainly based on egui
and image
.
We have a few pre-built binaries for Windows and MacOS on the releases page.
With Rust installed you can also
cargo install rvimage
to install the latest stable release. Additionally to the Rust toolchain, you need a c-compiler, make, and perl in your path, since we use the
ssh2-crate with the vendored-openssl
feature, see here for more info.
RV Image connects to
- SSH/SCP using the
ssh2
crate, - local folders that might be mounts of remote storage,
- http-servers spawned via
python -m http.server
, and - Azure blob storages*.
Example configuration for the connection types can be found below. Images are cached locally in a temporary directory.
When RV Image is started, also an http server is launched as aditional navigation option besides the graphical user interface. The default address is 127.0.0.1:5432
. If occupied, the port will be increased. When sending a
get-request to /file_label
the image file_label
is loaded. For this to work, file_label
must
be in the currently opened folder.
To configure RV Image open Settings
from the main menu. Many options can only be adapted after clicking
on Open in Editor
. The configuration is separated into user-specific and project-specific options.
The project specific options are persisted in the project file. The user-specific options are persisted
in %USERPROFILE%/.rvimage/rv_cfg_usr.toml
or $HOME/.rvimage/rv_cfg_usr.toml
depending on your operating system.
For SSH currently, only authorization with key-files without passphrase is supported.
[usr]
n_autosave = 2
current_pjr_path = "prjpath.json"
# "NoCache" for not caching at all or "FileCache" for caching files in a temp dir.
cache = "FileCache"
# Address of the http control server, default is 127.0.0.1:5432
# http_address = address:port
# If you do not want to use the temporary directory of your OS, you can add something else.
# tmpdir =
[usr.file_cache_args]
n_prev_images = 2 # number of images to be cached previous to the selected one
n_next_images = 8 # number of images to be cached following the selected one
n_threads = 4 # number of threads to be used for background file caching
[usr.ssh]
user = "your username"
ssh_identity_file_path = "somepath/.ssh/id_file_with_private_key"
[prj]
# We support the connections "Local", "Ssh", "PyHttp", or "AzureBlob"
connection = "Ssh"
[prj.ssh]
# Local folders can interactively be chosen via file dialog. Remote folders are restricted to one of the following list.
remote_folder_paths = [
"folder on your server",
"another folder"
]
address = "address:port" # port is usually 22
[prj.py_http_reader_cfg]
# The server is expected to be started via `python -m http.server` in some folder.
# The content of this folder is then accessible.
server_addresses = ['http://localhost:8000/']
[prj.azure_blob]
# With a connection string you can view the images inside a blob storage.
# The connection_string_path should point to file that contains just the
# connection string or a line with `CONNECTION_STRING = ` or `AZURE_CONNECTION_STRING = `.
connection_string_path = "connection_str.txt"
container_name = "images"
# The prefix is also called folder in the Microsoft Azure Storage Explorer.
# Currently, you cannot choose this interactively.
prefix = ""
RV Image comes with two labeling tools:
- Draw bounding boxes and polygons and export in the Coco format.
- Draw brush lines and export as Coco-file with run-length-encodings. Thereby, we ignore the
iscrowd=true
convention that usually comes with run-length-encoded annotations in Coco-files.
All annotations are also stored in the project file in json format.
Besides labeling tools we also provide means to filter the images to select from and different ways to zoom in and out.
You can zoom anytime with holding Ctrl and pressing + or -. Additionally, you can operate the mouse wheel while holding Ctrl.
You can also use the separate zoom tool and draw a box on the image area you want to see enlarged.
To move the zoomed area hold Ctrl and drag with the left mouse button.
You can filter for image files to appear in the left selection area. The entered string will reveal those images that contain the string in their pathname.
Besides based on the pathname, you can also filter based on the labels and attributes you have used:
nolabel
reveals all images that have not been labeled with the currently active tool.anylabel
reveals all images that have been labeled with the currently active tool.label(<label-name>)
reveals all images that have a label of the class<label-name>
for the currently active tool. For instance, if the bounding box tool is activelabel(foreground)
will reveal all images that contain bounding boxes or polygons of the classforeground
. Some special characters in the label names might lead to troubles.tool(<tool-name>)
reveals all images that have been labeled with the tool<tool-name>
. For instance,tool(Brush)
will reveal all images that have been labeled with the brush tool.attr(<attr-name>:<attr-val>)
reveals all images that have the attribute<attr-name>
set to<attr-val>
.attr(<attr-name>:<attr-val-min>-<attr-val-max)
reveals all images that have the attribute<attr-name>
set between<attr-val-min>
and<attr-val-max>
.
Filter strings can be combined with &&
, ||
, and !
. For instance
!nolabel
corresponds toanylabel
1055.png || label(cat)
reveals all iamges that either have a1055.png
as part of their full pathname or contain the labelcat
from the currently active labeling tool.
RV Image comes with a simple bounding box and polygon labeling tool that can export to and import from the Coco format.
For an import to work, the folder that contains the images needs to be opened beforehand. To filter for files that contain bounding boxes of a specific label, one can put label(<name-of-label>)
into the filter text field. Thereby, <name-of-label>
needs to be replaced by the real name of the label. To filter for unlabeled files use nolabel
. Filters including filename-strings can be combined with &&
, ||
, and !
.
There two main ways to draw a polygon or a box:
- One corner per left-click for a polygon. Finish by right-click. One left-click and one right-clicks for a box.
- Drag the left mouse button. A polygon will follow you mouse.
event | action |
---|---|
drag and release left mouse | draw polygon |
first left click | start drawing mode |
|
add polygon vertex |
right click | finish drawing box or polygon |
Alt + left click during box/polygon drawing | delete last vertex added |
left click on corner of box | start drawing mode and move vertex |
Ctrl + left click on box | select box |
Alt + left click on box | select box and deselect others and switch to currently selected label |
hold right button | move selected boxes |
Shift + left click on box | select all boxes with overlap with the maximal span of this box and other selected boxes |
Ctrl + A | select all boxes |
Delete | remove selected boxes |
Ctrl + D | deselect all boxes |
Ctrl + H | hide all boxes |
C | clone selected boxes at mouse position and move selection to new box |
Ctrl + C | copy all selected boxes to clipboard |
Ctrl + V | paste boxes without existing duplicate from clipboard |
V | activate auto-paste on image change |
Left⬅/Right➡/Up⬆/Down⬇ | move bottom right corner of all selected boxes |
Ctrl + Left⬅/Right➡/Up⬆/Down⬇ | move top left corner of all selected boxes |
Alt + Left⬅/Right➡/Up⬆/Down⬇ | move all selected boxes |
change label | labels of selected boxes/polygons are changed |
event | action |
---|---|
left click | draw circle if not in erase mode, else erase close brush stroke |
hold left mouse | draw brush if not in erase mode |
E | activate erase mode |
Ctrl + click with left mouse | select brush |
Ctrl + C/V/A/H/D | see bounding box tool |
Delete | delete selected strokes |
change label | labels of selected strokes are changed |
T/I | increase thickness/intensity |
Alt + T/I | decrease thickness/intensity |
* The connection to Azure blob storages has tokio
, futures
, azure_storage
, and azure_storage_blob
as additional dependencies, since the used Azure SDK is implemented async
hronously and needs tokio
. However, the rest of RV Image uses its own small threadpool implementation. Hence, the Azure blob storage connection is implemented as Cargo-feature azure_blob
that is enabled by default.