Repository: jveitchmichaelis/deeplabel Branch: master Commit: f5978a1349cf Files: 83 Total size: 564.5 KB Directory structure: gitextract_q_bu5e9m/ ├── .github/ │ └── workflows/ │ ├── build_osx.yml │ ├── build_ubuntu.yml │ └── build_windows.yml ├── .gitignore ├── .gitmodules ├── DeepLabel.pro ├── README.md ├── deploy_mac.sh ├── fix_paths_mac.py └── src/ ├── baseexporter.cpp ├── baseexporter.h ├── baseimporter.cpp ├── baseimporter.h ├── birdsaiimporter.cpp ├── birdsaiimporter.h ├── boundingbox.h ├── cliparser.cpp ├── cliparser.h ├── cliprogressbar.h ├── cocoexporter.cpp ├── cocoexporter.h ├── cocoimporter.cpp ├── cocoimporter.h ├── crc32.cpp ├── crc32.h ├── darknetexporter.cpp ├── darknetexporter.h ├── darknetimporter.cpp ├── darknetimporter.h ├── detection/ │ ├── detectoropencv.cpp │ ├── detectoropencv.h │ ├── detectorsetupdialog.cpp │ ├── detectorsetupdialog.h │ └── detectorsetupdialog.ui ├── exportdialog.cpp ├── exportdialog.h ├── exportdialog.ui ├── exporter.h ├── gcpexporter.cpp ├── gcpexporter.h ├── imagedisplay.cpp ├── imagedisplay.h ├── imagedisplay.ui ├── imagelabel.cpp ├── imagelabel.h ├── importdialog.cpp ├── importdialog.h ├── importdialog.ui ├── importer.h ├── kittiexporter.cpp ├── kittiexporter.h ├── labelproject.cpp ├── labelproject.h ├── labelrefinedialog.cpp ├── labelrefinedialog.h ├── labelrefinedialog.ui ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── mainwindow.ui ├── motimporter.cpp ├── motimporter.h ├── multitracker.cpp ├── multitracker.h ├── pascalvocexporter.cpp ├── pascalvocexporter.h ├── pascalvocimporter.cpp ├── pascalvocimporter.h ├── proto/ │ ├── example.pb.cc │ ├── example.pb.h │ ├── example.proto │ ├── feature.pb.cc │ ├── feature.pb.h │ └── feature.proto ├── refinerangedialog.cpp ├── refinerangedialog.h ├── refinerangedialog.ui ├── tfrecordexporter.cpp ├── tfrecordexporter.h ├── tfrecordimporter.cpp ├── tfrecordimporter.h ├── videoexporter.cpp └── videoexporter.h ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/workflows/build_osx.yml ================================================ name: Build OS X on: [push] jobs: build: runs-on: macos-latest steps: - uses: actions/checkout@v2 with: submodules: recursive - name: Install Qt 5 + OpenCV + protobuf run: brew install qt@5 opencv protobuf - name: Force link Qt run: brew link qt@5 --force - name: Compile protobuf messages run: protoc --proto_path ./src/proto --cpp_out ./src/proto feature.proto example.proto - name: Run QMake run: qmake -makefile -o Makefile DeepLabel.pro - name: Run Make run: make -j4 - name: Deploy run: bash deploy_mac.sh ./release - name: Archive production artifacts uses: actions/upload-artifact@v2 with: name: osx-release path: ./release/deeplabel.dmg ================================================ FILE: .github/workflows/build_ubuntu.yml ================================================ name: Build Ubuntu on: [push] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 with: submodules: recursive - name: Install Qt 5 + protobuf run: sudo apt-get update && sudo apt-get install -qq -y libprotobuf-dev qt5-default git build-essential protobuf-compiler cmake pkg-config libjpeg-dev libtiff5-dev libpng-dev - name: Clone OpenCV run: > git clone --branch 4.5.3 --depth 1 https://github.com/opencv/opencv; git clone --branch 4.5.3 --depth 1 https://github.com/opencv/opencv_contrib; - name: Compile OpenCV run: > cd opencv && mkdir build && cd build && cmake .. -DOPENCV_EXTRA_MODULES_PATH=../../opencv_contrib/modules -DBUILD_TESTS=OFF -DBUILD_PERF_TESTS=OFF .. -DCMAKE_BUILD_TYPE=RELEASE -DBUILD_EXAMPLES=OFF -DBUILD_DOCS=OFF -DBUILD_JAVA=OFF -DBUILD_opencv_apps=OFF -DBUILD_opencv_aruco=OFF -DBUILD_opencv_barcode=OFF -DBUILD_opencv_bgsegm=OFF -DBUILD_opencv_bioinspired=OFF -DBUILD_opencv_calib3d=OFF -DBUILD_opencv_datasets=OFF -DBUILD_opencv_dpm=OFF -DBUILD_opencv_dnn_superres=OFF -DBUILD_opencv_face=OFF -DBUILD_opencv_features2d=OFF -DBUILD_opencv_flann=OFF -DBUILD_opencv_fuzzy=OFF -DBUILD_opencv_gapi=OFF -DBUILD_opencv_highgui=ON -DBUILD_opencv_img_hash=OFF -DBUILD_opencv_intensity_transform=OFF -DBUILD_opencv_line_descriptor=OFF -DBUILD_opencv_mcc=OFF -DBUILD_opencv_objc_bindings_generator=OFF -DBUILD_opencv_objdetect=OFF -DBUILD_opencv_optflow=OFF -DBUILD_opencv_phase_unwrapping=OFF -DBUILD_opencv_photo=OFF -DBUILD_opencv_rgbd=OFF -DBUILD_opencv_saliency=OFF -DBUILD_opencv_shape=OFF -DBUILD_opencv_js_bindings_generator=OFF -DBUILD_opencv_freetype=OFF -DBUILD_opencv_quality=OFF -DBUILD_opencv_reg=OFF -DBUILD_opencv_stereo=OFF -DBUILD_opencv_stitching=OFF -DBUILD_opencv_structured_light=OFF -DBUILD_opencv_superres=OFF -DBUILD_opencv_surface_matching=OFF -DBUILD_opencv_text=OFF -DBUILD_opencv_ts=OFF -DBUILD_opencv_videostab=OFF -DBUILD_opencv_viz=OFF -DBUILD_opencv_wechat_qrcode=OFF -DBUILD_opencv_ximgproc=OFF -DBUILD_opencv_xobjdetect=OFF -DBUILD_opencv_xphoto=OFF -DBUILD_opencv_xfeatures2d=OFF && make -j4 && sudo make install - name: Compile protobuf messages run: protoc --proto_path ./src/proto --cpp_out ./src/proto feature.proto example.proto - name: Run QMake run: qmake -makefile -o Makefile DeepLabel.pro - name: Run Make run: make -j4 - name: Archive production artifacts uses: actions/upload-artifact@v2 with: name: linux-release path: ./release/deeplabel ================================================ FILE: .github/workflows/build_windows.yml ================================================ name: Build Windows on: [push] jobs: build: runs-on: windows-latest steps: - uses: actions/checkout@v2 with: submodules: recursive - name: Install Qt 5 and mingw run: choco install qt5-default mingw --confirm -r --no-progress - name: Clone protobuf run: git clone https://github.com/protocolbuffers/protobuf - name: Install protobuf run: > cd protobuf/cmake; mkdir build; cd build; $install_path=Resolve-Path ../../; cmake .. -Dprotobuf_BUILD_SHARED_LIBS=ON -Dprotobuf_BUILD_EXAMPLES=OFF -Dprotobuf_BUILD_TESTS=OFF -Dprotobuf_WITH_ZLIB=ON -Dprotobuf_BUILD_PROTOC_BINARIES=ON -DCMAKE_INSTALL_PREFIX="$install_path"; cmake --build . --parallel 4 --target install --config Release - name: Compile protobuf messages run: ./protobuf/bin/protoc.exe --proto_path ./src/proto --cpp_out ./src/proto feature.proto example.proto - name: Clone OpenCV run: > git clone --branch 4.5.3 --depth 1 https://github.com/opencv/opencv; git clone --branch 4.5.3 --depth 1 https://github.com/opencv/opencv_contrib - name: Compile OpenCV run: > cd opencv; mkdir build; cd build; $extra_path=Resolve-Path ../../opencv_contrib/modules; $install_path=Resolve-Path .; cmake .. -DOPENCV_EXTRA_MODULES_PATH="$extra_path" -DBUILD_TESTS=OFF -DBUILD_PERF_TESTS=OFF .. -DCMAKE_BUILD_TYPE=RELEASE -DBUILD_EXAMPLES=OFF -DBUILD_DOCS=OFF -DBUILD_JAVA=OFF -DBUILD_opencv_apps=OFF -DBUILD_opencv_aruco=OFF -DBUILD_opencv_barcode=OFF -DBUILD_opencv_bgsegm=OFF -DBUILD_opencv_bioinspired=OFF -DBUILD_opencv_calib3d=OFF -DBUILD_opencv_datasets=OFF -DBUILD_opencv_dpm=OFF -DBUILD_opencv_dnn_superres=OFF -DBUILD_opencv_face=OFF -DBUILD_opencv_features2d=OFF -DBUILD_opencv_flann=OFF -DBUILD_opencv_fuzzy=OFF -DBUILD_opencv_gapi=OFF -DBUILD_opencv_highgui=ON -DBUILD_opencv_img_hash=OFF -DBUILD_opencv_intensity_transform=OFF -DBUILD_opencv_line_descriptor=OFF -DBUILD_opencv_mcc=OFF -DBUILD_opencv_objc_bindings_generator=OFF -DBUILD_opencv_objdetect=OFF -DBUILD_opencv_optflow=OFF -DBUILD_opencv_phase_unwrapping=OFF -DBUILD_opencv_photo=OFF -DBUILD_opencv_quality=OFF -DBUILD_opencv_reg=OFF -DBUILD_opencv_rgbd=OFF -DBUILD_opencv_saliency=OFF -DBUILD_opencv_shape=OFF -DBUILD_opencv_js_bindings_generator=OFF -DBUILD_opencv_freetype=OFF -DBUILD_opencv_stereo=OFF -DBUILD_opencv_stitching=OFF -DBUILD_opencv_structured_light=OFF -DBUILD_opencv_superres=OFF -DBUILD_opencv_surface_matching=OFF -DBUILD_opencv_text=OFF -DBUILD_opencv_ts=OFF -DBUILD_opencv_videostab=OFF -DBUILD_opencv_viz=OFF -DBUILD_opencv_wechat_qrcode=OFF -DBUILD_opencv_ximgproc=OFF -DBUILD_opencv_xobjdetect=OFF -DBUILD_opencv_xphoto=OFF -DBUILD_opencv_xfeatures2d=OFF -DBUILD_opencv_world=ON -DCMAKE_INSTALL_PREFIX="$install_path"; cmake --build . --parallel 4 --config Release --target install - name: Run QMake run: C:/Qt/5.15.2/mingw81_64/bin/qmake.exe -makefile -o Makefile DeepLabel.pro - name: Run Make run: mingw32-make -f Makefile.Release - name: Archive production artifacts uses: actions/upload-artifact@v2 with: name: windows-release path: ./release/deeplabel ================================================ FILE: .gitignore ================================================ build/ *.pro.user* Makefile ui_* .moc .obj *.stash opencv protobuf ================================================ FILE: .gitmodules ================================================ [submodule "QtAwesome"] path = QtAwesome url = https://github.com/gamecreature/QtAwesome.git ================================================ FILE: DeepLabel.pro ================================================ #------------------------------------------------- # # Project created by QtCreator 2017-10-04T17:31:00 # #------------------------------------------------- QT += core gui sql testlib concurrent xml greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = deeplabel TEMPLATE = app # The following define makes your compiler emit warnings if you use # any feature of Qt which has been marked as deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 macx{ message("Mac") #PKG_CONFIG = /usr/local/bin/pkg-config CONFIG += c++17 # Build without FFMPEG unless you want a lot of pain later CONFIG += link_pkgconfig PKGCONFIG += protobuf # If you use pkg-config, *everything* gets linked. Wasteful. INCLUDEPATH += /usr/local/include/opencv4 LIBS += -L/usr/local/opt/opencv/lib/ LIBS += -lopencv_core -lopencv_highgui -lopencv_imgproc -lopencv_imgcodecs -lopencv_tracking -lopencv_video -lopencv_videoio -lopencv_dnn } unix:!macx{ message("Linux") #CONFIG += link_pkgconfig #PKGCONFIG += opencv4 CONFIG += c++17 INCLUDEPATH += /usr/local/include/opencv4 LIBS += -L/usr/local/lib -lprotobuf -lopencv_core -lopencv_highgui -lopencv_imgproc -lopencv_imgcodecs -lopencv_tracking -lopencv_video -lopencv_videoio -lopencv_dnn } win32{ message("Windows") DEFINES += PROTOBUF_USE_DLLS defined(WITH_CUDA){ message("Building with CUDA") CONFIG += WITH_CUDA INCLUDEPATH += "$$_PRO_FILE_PWD_/opencv/build_cuda/include" LIBS += -L"$$_PRO_FILE_PWD_/opencv/build_cuda/x64/vc16/lib" }else{ INCLUDEPATH += "$$_PRO_FILE_PWD_/opencv/build/include" LIBS += -L"$$_PRO_FILE_PWD_/opencv/build/x64/vc16/lib" } INCLUDEPATH += "$$_PRO_FILE_PWD_/protobuf/include" LIBS += -L"$$_PRO_FILE_PWD_/protobuf/lib" #QMAKE_CXXFLAGS += "/std:c++17 /permissive-" CONFIG(debug, debug|release) { LIBS += -lopencv_world453d -llibprotobufd }else{ LIBS += -lopencv_world453 -llibprotobuf } } # For building in a single folder CONFIG(debug, debug|release) { CONFIG(WITH_CUDA){ DESTDIR = debug_cuda }else{ DESTDIR = debug } OBJECTS_DIR = .obj_debug MOC_DIR = .moc_debug }else { DEFINES += QT_NO_DEBUG_OUTPUT CONFIG(WITH_CUDA){ message("Building with CUDA") DESTDIR = release_cuda }else{ DESTDIR = release } OBJECTS_DIR = .obj MOC_DIR = .moc } INCLUDEPATH += "$$_PRO_FILE_PWD_/src" VPATH = "$$_PRO_FILE_PWD_/src" SOURCES += \ src/crc32.cpp \ src/main.cpp \ src/mainwindow.cpp \ src/labelproject.cpp \ src/imagelabel.cpp \ src/kittiexporter.cpp \ src/darknetexporter.cpp \ src/exportdialog.cpp \ src/multitracker.cpp \ src/baseexporter.cpp \ src/baseimporter.cpp \ src/birdsaiimporter.cpp \ src/cliparser.cpp \ src/cocoexporter.cpp \ src/darknetimporter.cpp \ src/pascalvocimporter.cpp \ src/proto/example.pb.cc \ src/proto/feature.pb.cc \ src/gcpexporter.cpp \ src/imagedisplay.cpp \ src/importdialog.cpp \ src/motimporter.cpp \ src/pascalvocexporter.cpp \ src/detection/detectoropencv.cpp \ src/detection/detectorsetupdialog.cpp \ src/refinerangedialog.cpp \ src/cocoimporter.cpp \ src/tfrecordexporter.cpp \ src/tfrecordimporter.cpp \ src/videoexporter.cpp HEADERS += \ src/cliprogressbar.h \ src/crc32.h \ src/importer.h \ src/mainwindow.h \ src/labelproject.h \ src/imagelabel.h \ src/boundingbox.h \ src/kittiexporter.h \ src/darknetexporter.h \ src/exportdialog.h \ src/multitracker.h \ src/baseexporter.h \ src/baseimporter.h \ src/birdsaiimporter.h \ src/cliparser.h \ src/cocoexporter.h \ src/darknetimporter.h \ src/exporter.h \ src/gcpexporter.h \ src/imagedisplay.h \ src/importdialog.h \ src/motimporter.h \ src/pascalvocexporter.h \ src/detection/detectoropencv.h \ src/detection/detectorsetupdialog.h \ src/pascalvocimporter.h \ src/proto/example.pb.h \ src/proto/feature.pb.h \ src/refinerangedialog.h \ src/cocoimporter.h \ src/tfrecordexporter.h \ src/tfrecordimporter.h \ src/videoexporter.h FORMS += \ src/importdialog.ui \ src/mainwindow.ui \ src/exportdialog.ui \ src/imagedisplay.ui \ detection/detectorsetupdialog.ui \ src/refinerangedialog.ui include(QtAwesome/QtAwesome/QtAwesome.pri) # Deploy apps in OS X and Windows isEmpty(TARGET_EXT) { win32 { TARGET_CUSTOM_EXT = .exe } macx { TARGET_CUSTOM_EXT = .app } } else { TARGET_CUSTOM_EXT = $${TARGET_EXT} } CONFIG( debug, debug|release ) { # debug DEPLOY_TARGET = $$shell_quote($$shell_path($${OUT_PWD}/debug/$${TARGET}$${TARGET_CUSTOM_EXT})) } else { # release DEPLOY_TARGET = $$shell_quote($$shell_path($${OUT_PWD}/release/$${TARGET}$${TARGET_CUSTOM_EXT})) } win32 { DEPLOY_COMMAND = windeployqt.exe } macx { DEPLOY_COMMAND = macdeployqt } # # Uncomment the following line to help debug the deploy command when running qmake # warning($${DEPLOY_COMMAND} $${DEPLOY_TARGET}) # Use += instead of = if you use multiple QMAKE_POST_LINKs win32 { QMAKE_POST_LINK = $${DEPLOY_COMMAND} $${DEPLOY_TARGET} } macx { QMAKE_POST_LINK = $${DEPLOY_COMMAND} $${DEPLOY_TARGET} } ================================================ FILE: README.md ================================================ # DeepLabel [![Build OS X](https://github.com/jveitchmichaelis/deeplabel/actions/workflows/build_osx.yml/badge.svg)](https://github.com/jveitchmichaelis/deeplabel/actions/workflows/build_osx.yml) [![Build Ubuntu](https://github.com/jveitchmichaelis/deeplabel/actions/workflows/build_ubuntu.yml/badge.svg)](https://github.com/jveitchmichaelis/deeplabel/actions/workflows/build_ubuntu.yml)[![Build Windows](https://github.com/jveitchmichaelis/deeplabel/actions/workflows/build_windows.yml/badge.svg)](https://github.com/jveitchmichaelis/deeplabel/actions/workflows/build_windows.yml) DeepLabel is a cross-platform tool for annotating images with labelled bounding boxes. A typical use-case for the program is labelling ground truth data for object-detection machine learning applications. DeepLabel runs as a standalone app and compiles on Windows, Linux and Mac. DeepLabel is written in C++ and is resource-efficient, typically using less than 100MB RAM to run. There is a GUI or you can run on the command line for batch/automated processing. Deeplabel also supports running inference using state-of-the-art object detection models like Faster-RCNN and YOLOv4. With support out-of-the-box for CUDA, you can quickly label an entire dataset using an existing model. **If you use DeepLabel for research or commercial purposes, please cite here!** [![DOI](https://zenodo.org/badge/105791274.svg)](https://zenodo.org/badge/latestdoi/105791274) Download the [latest release](https://github.com/jveitchmichaelis/deeplabel/releases/latest)! If you are an OS X user, check the `Actions` tab to download an automated and self-contained DMG build. The Github CI runs on every push and attempts to build DeepLabel for Windows, Mac and Linux. You can check the action workflows for hints on how to compile everything if you're having trouble. **Note: Deeplabel for Windows now packages CUDA and CUDNN for inference. This results an enormous distributable size as the cudnn inference libraries are 600MB+ alone. The CUDA runtime adds another 300MB. I'm looking into uploading simultaneous non-CUDA releases to save space. The alternative is to ask you to install CUDA and CUDNN yourself, but you'd need the correct version which is a pain.** Ready made binaries for Windows and OS X are on the release page. It is recommended that you build for Linux yourself, but it's not difficult. ![Deeplabel Interface](gui_example.png) ## Workflow DeepLabel was built with convenience in mind. Image locations, classes and labels are stored in a local sqlite database (called a _project_, in the application). When a label is added or removed, this is immediately reflected in the database. A typical workflow for DeepLabel is: 1. Create a new project database 2. Add images, or import an existing project in a variety of common ML formats 3. Load in a class list, or manually add classes 4. Label/inspect the images 5. Export data in the desired format ## Command Line Interface Deeplabel now has a convenient command line interface to facilitate import and export of data: ``` (base) PS C:\Users\Josh> deeplabel.exe -h Usage: deeplabel.exe [options] mode Options: -?, -h, --help Displays help on commandline options. --help-all Displays help including Qt specific options. -v, --version Displays version information. -f, --format <[kitti, darknet, gcp, voc, coco, mot export format , birdsai, tfrecord]> -o, --output output folder -i, --input label database -s, --split validation split percentage --no-subfolders export directly to specified folder --prefix filename prefix -n, --names names file --bucket GCP bucket --local use local paths for GCP export --export-map export label.pbtxt file --shuffle shuffle images when splitting --append-labels append to label files --export-unlabelled export images without labels --images import image path/folder --annotations import annotation path/folder --import-unlabelled import images without labels --overwrite overwrite existing databases --records mask for TF Records (* wildcard) Arguments: mode [export, import] ``` For example, if you want to export a dataset to TFRecord: ``` deeplabel.exe export -i labels.lbdlb -f TFRecord -n project.names -o ./output/ ``` ## Data import Currently you can import data in the following formats: * Darknet (provide image list and names) * COCO (provide an annotation .json file and image folder) * MOT * TFRecord (parsing works, but full import is not possible yet) * Pascal VOC ## Data export Currently you can export in: * KITTI (e.g. for Nvidia DIGITS) * Darknet for YOLO * Pascal VOC * COCO (experimental) * Google Cloud Platform (e.g. for AutoML) * TFRecord (for the Tensorflow Object Detection library) * Note this uses protobuf directly and there is _no_ dependency on Tensorflow. I believe this is one of the few implementations of TFRecord writing in c++. * Video (experimental, command line only) Deeplabel treats your data as "golden" and does not make any attempt to modify it directly. This is a safe approach to avoid accidental corruption of a dataset that you spent months collating. As such, when you export labels, a copy of your data will be created with associated label files. For example, KITTI requires frames to be numerically labelled. In the future, augmentation may also be added, which is another reason to **not** modify your existing images. When exporting to darknet, you should specify an existing "names" file so that your output labels have consistent class IDs. Similarly, when you export to Pascal VOC, you have the option of exporting a label map file which maps class IDs to labels. This file is quite easy to generate yourself (and you may already have it). The format is: ``` { item { name: some_class id: 1 displayname: some_class } ``` DeepLabel can automatically split your data into train and validation sets, you can choose what fraction to use (you can set 0% or 100% if you just want a test or validation set). Since the labelling metadata is in the sqlite database, it should be fairly easy to write a Python script (or whatever) to convert the output to your preferred system. Many frameworks will accept Pascal VOC formatted data, so that's a good start. ## Model inference (automatic tagging) DeepLabel now supports automatic image tagging from a pre-trained model. A good approach for rapidly tagging thousands of images is to train a "rough" model on a small subset of your data, use that model to tag more data, correct the labels as required, and repeat. Over time, the model will get better and better and you will need to make fewer corrections. ### Supported models You can load in a Darknet-type model, for example Yolov3, Yolov3-spp and Yolov3-Tiny or a Tensorflow model. Most of the standard Tensorflow models are supported e.g. Faster-RCNN, Mobilenet-SSD. Currently the assumption is that the model ends with a `DetectionOutput` layer. This is an Nx7 sized tensor where `N` is the number of output labels, after non-maximum suppression has been applied (typically 100 for stock models). The columns are `batch id, class id, confidence, box coords`. You need to provide: * The model configuration file (`.cfg, .pbtxt`) * The model weights (`.weights, .pb`) * A names file (`.names`) The extension doesn't really matter, but these are the standard ones. **Note: ensure that your names file corresponds to the expect label IDs that your model outputs. For example, Darknet uses an 80-class file, Tensorflow models often use a 91-class file, MobileNet-SSD outputs labels starting from 1, Faster-RCNN outputs labels starting from 0, etc.** You can then run inference on a single image (the magic wand icon), or an entire project (`Detection->Run on Project`). On a modern CPU, Yolov3 takes around 0.5 seconds to tag a full HD image. DeepLabel will use OpenCV's OpenCL backend by default (you can select CPU if necessary), which should provide some acceleration on GPUs. If you're not seeing any detections, you can adjust the confidence threshold (`Detection->Set Threshold`). If your detection boxes look right, but the classe labels are wrong, check your names file is correct. Download Tensorflow models for testing from OpenCV [here](https://github.com/opencv/opencv/wiki/TensorFlow-Object-Detection-API). ### Target You can run models on CPU or OpenCL. All models will work on CPU. You may see a speed up with OpenCL, but the CPU backend is far more heavily optimised (and typically is better than other framework's CPU performance). OpenCL support is somewhat experimental and you may get an out-of-memory error (and Deeplabel will unceremoniously crash). Try with CPU if this happens. Typical performance is anywhere from 50 ms for Tiny Yolov3 to a couple of seconds for Faster-RCNN ## 16-bit File Handling Deeplabel supports 16-bit images and will automatically scale the colours to 8-bit grayscale. You can optionally apply a colourmap to a single channel image, which may improve contrast. In the future, support should be added for OpenCV's Tensorflow backend. ## Bounding box tracking and refinement DeepLabel supports multi-threaded object tracking for quickly labelling video sequences. Simply label the first frame, initialise the tracker and select "propagate on next image". The software will initialise a tracker for each bounding box and attempt to track it in the next frame. If tracking is lost, you can re-label the offending image, restart the tracker and keep going. In this way, you can quickly label thousands of images in minutes. DeepLabel also supports bounding box refinement using some simple thresholding and contour segmentation techniques. This was designed for labelling thermal infrared images, but it should work on colour images too. It works best if the object has a high contrast. It will also probably fail if you have two overlapping objects that look very similar. An experimental foreground/background segmenter is being tested, but it seems to be a bit overenthusiastic right now. ## Video support DeepLabel currently supports videos by a brute force route. You can load in a video which will be automatically split into JPEG frames and then loaded into your label database. Currently the entire video will be loaded, though in the future functionality will likely be similar to VOTT with frame skip options and no need to split the video beforehand. Note that when dealing with videos you will typically need to export them as separate frames anyway. Any video format that OpenCV (and its backends) can open should work. Usage -- Using the software should be fairly straightforward. Once you've created a project database and added images to it, you can get on with the fun part of adding bounding boxes. First, add the classes that you want. DeepLabel operates in two modes: draw and select. In **draw** mode, you can click to define the corners of a bounding box rectangle. If you're happy with the box, hit space to confirm. The rectangle will be added to the image with a class label. If you need to delete a label, switch to **select** mode. Click on a rectangle, it will highlight green, the hit delete or backspace to remove it. All changes are immediately reflected in the database. **Navigate** through images using the left/right or a/d keys. You can use ctrl+left/right to quickly advance through your dataset. You should find a/d to be quite a natural way of navigating without moving your left hand. There is a progress bar to indicate how far through the dataset you've labelled. Once you're done labelling, open the export menu to copy and rename your images and generate label files. When you export, you need to tell Deeplabel what classes you wish to export (typically via a `.names` file). This means that you can consistently export multiple label files (e.g. one per video sequence) and have the class/class IDs match up. Building from source -- It's recommended that you use Qt5, but Qt4 will probably work. You need to have Qt's SQL extensions installed. **OpenCV Requirements** This is mostly a pure Qt project, but there are some limitations to what Qt can do with images. In particular, scaling sucks (even with `Qt::SmoothTransform`). Qt's image reader is also not particularly robust, so OpenCV is used there. OpenCV is also used for image augmentation. On OS X or Linux it's expected that you have `pkg-config` installed to handle dependencies. You need to compile OpenCV with contrib (`-DOPENCV_EXTRA_MODULES_PATH`) for object tracking. You should also compile with (`-DOPENCV_GENERATE_PKGCONFIG`). Only OpenCV 4+ is supported due to API changes. Make sure you checkout the same tagged release for the main repository and the contrib repository. ``` bash git clone https://github.com/opencv/opencv git clone https://github.com/opencv/opencv_contrib cd opencv && git checkout 4.5.3 && cd ../ cd opencv_contrib && git checkout 4.5.3 && cd ../ cd opencv mkdir build && cd build cmake .. -DBUILD_TESTS=OFF -DBUILD_PERF_TESTS=OFF -DOPENCV_EXTRA_MODULES_PATH=../../opencv_contrib/modules make -j8 sudo make install ``` On Mac, Homebrew automatically include pkg-config support and the contrib packages. **Linux** [See Github Action for representative build instructions.](https://github.com/jveitchmichaelis/deeplabel/blob/master/.github/workflows/build_ubuntu.yml) Build opencv using your preferred method (e.g. above). You need Qt5 installed - not just Qt Creator. ``` sudo apt install git build-essential qt5-default libprotobuf-dev protobuf-compiler ``` Proto files are already compiled within the `src/proto` folder, but if you need to, you can compile with: ``` protoc --proto_path ./src/proto --cpp_out ./src/proto feature.proto example.proto ``` Clone the repository, then: ```bash git submodule update --init --recursive qmake -makefile -o Makefile DeepLabel.pro make -j4 ``` **Mac** Install dependencies using Homebrew: ``` bash brew install qt opencv protobuf ``` Note that qt is not linked by default, so either force link it (`brew link -f qt`) or follow the post-install instructions to see where qmake is installed. Clone the repo, open the pro file in Qt Creator and build. Deployment is automatic on Windows and OS X. Alternatively: ```bash git submodule update --init --recursive qmake -makefile -o Makefile DeepLabel.pro make -j4 ``` `madeployqt` is automatically run after compilation, and on OS X will build a `.dmg` file. This does have the irritating side effect of linking and copying every `dylib` OpenCV has to offer so feel free to dig into the package and delete some of the dylibs that you don't need. This is a tradeoff between output file size and convenience. An extra script is provided to fix paths to certain libraries on OS X. **Windows** Unfortunately you need to install OpenCV from source, because the official binary releases don't include the contrib modules (which include tracking algorithms and DNN support). Or just download a DeepLabel release from [here](https://github.com/jveitchmichaelis/deeplabel/releases). You will also need protobuf installed - make sure you compile with DLLs enabled, not static libraries. Once you've installed OpenCV...(!) Clone the repo, update the submodules to fetch QtAwesome, open the pro file in Qt Creator and modify the paths to your opencv install. Build as normal. Make sure you copy all the OpenCV DLLs after install. Notes -- #### Overlapping bounding boxes DeepLabel doesn't care if your bounding boxes overlap, but selecting overlapping bounding boxes is a tricky problem from a UI point of view. Currently the solution is simple: all rectangles containing the cursor will be highlighted and if you hit delete, the most recent one will be deleted. #### Image paths Image paths in the database are stored relative to the database location. This means you can easily copy over files to another system, provided you keep the relative structure of the files. #### Support for other descriptors (e.g. occluded, truncated) In the future I'd like to add the ability to mark labels as occluded or truncated. I haven't decided on the best way to implement this yet - most detector networks don't use this information, but it's useful for stats. #### Database schema DeepLabel uses a simple relational database with the following schema: CREATE TABLE classes (class_id INTEGER PRIMARY KEY ASC, name varchar(32)) CREATE TABLE images (image_id INTEGER PRIMARY KEY ASC, path varchar(256)) CREATE TABLE labels (label_id INTEGER PRIMARY KEY ASC, image_id int, class_id int, x int, y int, width int, height int) These fields are the bare minimum and more may be added later (see note on descriptors above). It may also be useful to include metadata about images for statistics purposes. #### License This code is MIT licensed - feel free to fork and use without restriction, commercially or privately, but please do cite. Copyright Josh Veitch-Michaelis 2017 - present. ================================================ FILE: deploy_mac.sh ================================================ #!/usr/bin/env bash build_folder=$1 app_path=$build_folder/DeepLabel.app macdeployqt $app_path python fix_paths_mac.py $app_path/Contents/MacOS/DeepLabel hdiutil create -volname DeepLabel -srcfolder $app_path -ov -format UDZO $build_folder/deeplabel.dmg ================================================ FILE: fix_paths_mac.py ================================================ import subprocess import os import sys from shutil import copyfile executable = sys.argv[1] app_folder = os.path.join(*executable.split('/')[:-3]) content_folder = os.path.join(app_folder, "Contents") framework_path = os.path.join(content_folder, "Frameworks") print(executable) print("Working in {} ".format(app_folder)) def file_in_folder(file, folder): return os.path.exists(os.path.join(folder, file)) def otool(s): o = subprocess.Popen(['/usr/bin/otool', '-L', s], stdout=subprocess.PIPE) for l in o.stdout: l = l.decode() if l[0] == '\t': path = l.split(' ', 1)[0][1:] if "@executable_path" in path: path = path.replace("@executable_path", "") path = os.path.join(content_folder, path[4:]) if "@loader_path" in path: path = path.replace("@loader_path", framework_path) if "@rpath" in path: path = path.replace("@rpath", framework_path) dependency_dylib_name = os.path.split(path)[-1] if "usr/local" in path: if app_folder in s: print("Warning: {} depends on {}".format(s, path)) if file_in_folder(dependency_dylib_name, framework_path): print("Dependent library {} is already in framework folder".format(dependency_dylib_name)) print("Running install name tool to fix {}.".format(s)) if dependency_dylib_name == os.path.split(s)[-1]: _ = subprocess.Popen(['install_name_tool', '-id', os.path.join("@loader_path", dependency_dylib_name), s], stdout=subprocess.PIPE) _ = subprocess.Popen(['install_name_tool', '-change', path, os.path.join("@loader_path", dependency_dylib_name), s], stdout=subprocess.PIPE) else: pass yield path need = set([executable]) done = set() while need: needed = set(need) need = set() for f in needed: need.update(otool(f)) done.update(needed) need.difference_update(done) ================================================ FILE: src/baseexporter.cpp ================================================ #include "baseexporter.h" BaseExporter::BaseExporter(LabelProject *project, QObject *parent) : QObject(parent) { this->project = project; } void BaseExporter::disableProgress(bool disable){ disable_progress = disable; } void BaseExporter::setValidationSplit(bool split){ validation_split = split; } void BaseExporter::splitData(float split, bool shuffle, int seed){ if(split < 0 || split > 1){ qCritical() << "Invalid split fraction, should be [0,1]"; } if(shuffle){ std::random_device rd; std::mt19937 generator(rd()); generator.seed(static_cast(seed)); std::shuffle(images.begin(), images.end(), generator); } int pivot = static_cast(images.size() * split); validation_set = images.mid(0, pivot); train_set = images.mid(pivot); qDebug() << "Split: " << split; if(split > 0){ qInfo() << train_set.size() << " images selected for train set."; qInfo() << validation_set.size() << " images selected for validation set."; }else{ qInfo() << train_set.size() << " images selected for output."; } } void BaseExporter::setExportUnlabelled(bool res){ export_unlabelled = res; bool relative_path = true; if(export_unlabelled){ project->getImageList(images, relative_path); }else{ project->getLabelledImageList(images, relative_path); } qDebug() << "Selected " << images.size() << " images"; } bool BaseExporter::setOutputFolder(const QString folder, bool no_subfolders){ if(folder == "") return false; output_folder = folder; //Make output folder if it doesn't exist if (!QDir(output_folder).exists()){ qInfo() << "Making output folder" << output_folder; QDir().mkpath(output_folder); } if(!no_subfolders){ //Make the training and validation folders train_folder = QDir::cleanPath(output_folder+"/train"); if (!QDir(train_folder).exists()){ qInfo() << "Making training folder" << train_folder; QDir().mkpath(train_folder); } if(validation_split){ val_folder = QDir::cleanPath(output_folder+"/val"); if (!QDir(val_folder).exists()){ qInfo() << "Making validation folder" << val_folder; QDir().mkpath(val_folder); } val_label_folder = QDir::cleanPath(val_folder); val_image_folder = QDir::cleanPath(val_folder); } train_label_folder = QDir::cleanPath(train_folder); train_image_folder = QDir::cleanPath(train_folder); }else{ train_folder = QDir::cleanPath(output_folder); val_folder = QDir::cleanPath(output_folder); val_label_folder = QDir::cleanPath(output_folder); val_image_folder = QDir::cleanPath(output_folder); train_label_folder = QDir::cleanPath(output_folder); train_image_folder = QDir::cleanPath(output_folder); qDebug() << "Output all to" << train_image_folder; } return true; } void BaseExporter::setFilenamePrefix(QString prefix){ if(prefix != ""){ filename_prefix = prefix; } } bool BaseExporter::saveImage(cv::Mat &image, const QString output, const double scale_x, const double scale_y){ if(image.rows == 0 || image.cols == 0){ qCritical() << "Empty image "; return false; } if(scale_x > 0 && scale_y > 0) cv::resize(image, image, cv::Size(), scale_x, scale_y); std::vector compression_params; // Png compression - maximum is super slow // TODO: add support to adjust this if(output.split(".").last().toLower() == "png"){ compression_params.push_back(cv::IMWRITE_PNG_COMPRESSION); compression_params.push_back(6); } return cv::imwrite(output.toStdString(), image, compression_params); } ================================================ FILE: src/baseexporter.h ================================================ #ifndef BASEEXPORTER_H #define BASEEXPORTER_H #include #include #include #include #include #include #include #include #include enum export_image_type{ EXPORT_UNASSIGNED, EXPORT_TRAIN, EXPORT_VAL, EXPORT_TEST }; class BaseExporter : public QObject { Q_OBJECT public: explicit BaseExporter(LabelProject *project, QObject *parent = nullptr); void disableProgress(bool disable); signals: void export_progress(int); public slots: void splitData(float split=1, bool shuffle=false, int seed=42); bool setOutputFolder(QString folder, bool no_subfolders=false); void setExportUnlabelled(bool res); void setAppendLabels(bool res){append_labels = res;} void setValidationSplit(bool split); void setFilenamePrefix(QString prefix); virtual void process() = 0; protected: LabelProject *project; QList train_set; QList validation_set; QList images; QString train_folder; QString train_label_folder; QString train_image_folder; QString val_folder; QString val_label_folder; QString val_image_folder; QString output_folder; QString filename_prefix = ""; std::map id_map; int image_id; int label_id; bool disable_progress = false; bool append_labels = false; bool validation_split = false; bool export_unlabelled = false; bool saveImage(cv::Mat &image, const QString output, const double scale_x = -1.0, const double scale_y = -1.0); }; #endif // BASEEXPORTER_H ================================================ FILE: src/baseimporter.cpp ================================================ #include "baseimporter.h" BaseImporter::BaseImporter(QObject *parent) : QObject(parent) { } void BaseImporter::setImportUnlabelled(bool import){ import_unlabelled = import; } void BaseImporter::setRootFolder(QString folder){ label_root = folder; } void BaseImporter::addAsset(QString image_path, QList boxes){ if(boxes.size() == 0 && !import_unlabelled) return; if(project->addAsset(image_path)){ for(auto &box : boxes){ project->addLabel(image_path, box); } } } QList BaseImporter::readLines(QString path){ QFile file(path); QList lines = {}; if (file.open(QFile::ReadOnly)) { while (!file.atEnd()){ auto line = QString(file.readLine()).simplified(); lines.append(line); } } return lines; } ================================================ FILE: src/baseimporter.h ================================================ #ifndef BASEIMPORTER_H #define BASEIMPORTER_H #include #include #include #include #include #include class BaseImporter : public QObject { Q_OBJECT public: explicit BaseImporter(QObject *parent = nullptr); void import(){}; void setRootFolder(QString folder); void setImportUnlabelled(bool import); signals: protected: bool import_unlabelled = false; QString label_root; LabelProject *project; void addAsset(QString image_path, QList boxes); QList readLines(QString path); public slots: }; #endif // BASEIMPORTER_H ================================================ FILE: src/birdsaiimporter.cpp ================================================ #include "birdsaiimporter.h" void BirdsAIImporter::import(QString sequence_folder, QString annotation_folder){ QDir seq_dir(sequence_folder); // Find all sequence folders QDirIterator it(sequence_folder, QDir::Dirs); QList subfolders; while (it.hasNext()) { auto subfolder = QDir(it.next()).canonicalPath(); subfolders.append(subfolder); } if(subfolders.size() == 0){ qWarning() << "Couldn't find any sequences in " << sequence_folder; return; } subfolders.removeDuplicates(); subfolders.sort(); for(auto &subfolder : subfolders){ qInfo() << "Checking: " << subfolder; auto sequence_name = QFileInfo(subfolder).baseName(); auto annotation_dir = QDir(annotation_folder); QString annotation_file = annotation_dir .absoluteFilePath(QString("%1.csv") .arg(sequence_name)); qDebug() << "Looking for: " << annotation_file; if(annotation_dir.exists(annotation_file)){ // Find images: auto labels = getLabels(annotation_file); QList> label_list; QList image_list; qInfo() << "Adding annotations from: " << annotation_file; for(auto &image : QDir(subfolder).entryList(QDir::Files)){ qDebug() << "Adding labels for" << image; // Extract image ID, ignoring leading zeros auto split_file = QFileInfo(image).baseName().split("_"); int image_id = split_file.back().toInt(); // Get boxes for this ID and add to DB auto boxes = findBoxes(labels, image_id); QString abs_image_path = QDir(subfolder).absoluteFilePath(image); if(boxes.empty() && !import_unlabelled){ continue; } label_list.append(boxes); image_list.append(abs_image_path); } project->addLabelledAssets(image_list, label_list); }else{ qWarning() << "Failed to find annotation file: " << annotation_file; } } } QList BirdsAIImporter::findBoxes(QVector labels, int id){ QList boxes = {}; // , , , , , , , , etc for(auto &label : labels){ if(label.at(0).toInt() != id){ continue; } BoundingBox bbox; /* https://sites.google.com/view/elizabethbondi/dataset * -1: unknown, * 0: human, * 1: elephant, * 2: lion, * 3: giraffe, * 4: dog, * 5: crocodile, * 6: hippo, * 7: zebra, * 8: rhino */ int label_species = label.at(7).toInt(); bbox.classid = label_species + 2; // Since in the database they're 1-indexed bbox.classname = project->getClassName(bbox.classid); if(bbox.classname == ""){ qWarning() << "Class ID " << bbox.classid << " not found in names file."; } auto top_left = QPoint(label.at(2).toDouble(), label.at(3).toDouble()); auto bottom_right = top_left + QPoint(label.at(4).toDouble(), label.at(5).toDouble()); bbox.rect = QRect(top_left, bottom_right); boxes.append(bbox); } return boxes; } ================================================ FILE: src/birdsaiimporter.h ================================================ #ifndef BIRDSAIIMPORTER_H #define BIRDSAIIMPORTER_H #include "motimporter.h" class BirdsAIImporter : public MOTImporter { public: explicit BirdsAIImporter(LabelProject *project, QObject *parent = nullptr) : MOTImporter(project, parent){ this->project = project; } void import(QString sequence_folder, QString annotation_folder); private: QList findBoxes(QVector labels, int id); }; #endif // BIRDSAIIMPORTER_H ================================================ FILE: src/boundingbox.h ================================================ #ifndef BOUNDINGBOX_H #define BOUNDINGBOX_H #include #include enum SelectedEdge { EDGE_LEFT, EDGE_TOP, EDGE_RIGHT, EDGE_BOTTOM, EDGE_NONE, }; enum SelectedCorner { CORNER_TOPLEFT, CORNER_TOPRIGHT, CORNER_BOTTOMLEFT, CORNER_BOTTOMRIGHT, CORNER_NONE, }; struct BoundingBox{ QRect rect = QRect(0,0,0,0); QString classname = ""; int occluded = 0; bool truncated = false; int classid = 0; double confidence = 0; // Drawing helpers bool is_selected = false; SelectedEdge selected_edge = EDGE_NONE; SelectedCorner selected_corner = CORNER_NONE; // ID int label_id = -1; }; inline QString printBoundingBox(BoundingBox box){ return QString("%1, xy(%2, %3) w: %4 h: %5") .arg(box.classname) .arg(box.rect.left()) .arg(box.rect.top()) .arg(box.rect.width()) .arg(box.rect.height()); } #endif // BOUNDINGBOX_H ================================================ FILE: src/cliparser.cpp ================================================ #include "cliparser.h" CliParser::CliParser(QObject *parent) : QObject(parent) { SetupOptions(); } void CliParser::SetupOptions(){ exportFormatOption = new QCommandLineOption({"f", "format"}, "export format", "kitti, darknet, gcp, voc, coco, mot, birdsai, tfrecord"); exportOutputFolder = new QCommandLineOption({"o", "output"}, "output folder", "folder path"); exportInputFile = new QCommandLineOption({"i", "input"}, "label database", "file path"); exportValidationSplit = new QCommandLineOption({"s", "split"}, "validation split percentage", "percentage", "20"); exportNoSubfolders = new QCommandLineOption("no-subfolders", "export directly to specified folder"); exportFilePrefix = new QCommandLineOption("prefix", "filename prefix", "prefix", ""); exportNamesFile = new QCommandLineOption({"n", "names"}, "names file", "file path"); exportGCPBucket = new QCommandLineOption("bucket", "GCP bucket"); exportGCPLocal = new QCommandLineOption("local", "use local paths for GCP export"); exportPascalVOCLabelMap = new QCommandLineOption("export-map", "export label.pbtxt file"); exportShuffleImages = new QCommandLineOption("shuffle", "shuffle images when splitting"); exportAppendLabels = new QCommandLineOption("append-labels", "append to label files"); exportUnlabelledImages = new QCommandLineOption("export-unlabelled", "export images without labels"); exportVideoFilename = new QCommandLineOption("video-filename", "video output filename", "filename", "out.mp4"); exportVideoFourcc = new QCommandLineOption("fourcc", "video codec fourcc", "codec", "h264"); exportVideoFps = new QCommandLineOption("fps", "video framerate", "fps", "10"); exportVideoColourmap = new QCommandLineOption("colourmap", "video colourmap", "colourmap", "Inferno"); exportVideoSize = new QCommandLineOption("videosize", "video size: width, height", "w,h", "1280,720"); exportVideoDisplayBoxes = new QCommandLineOption("display-boxes", "display boxes in output", "on, off", "on"); exportVideoDisplayNames = new QCommandLineOption("display-names", "display class names", "on, off", "on"); importImages = new QCommandLineOption("images", "import image path/folder", "images"); importRelativePath = new QCommandLineOption("relative-path", "relative file path (for darknet)", "relative"); importTFRecordMask = new QCommandLineOption("records", "mask for TF Records (* wildcard)", "images"); importAnnotations = new QCommandLineOption("annotations", "import annotation path/folder", "annotations"); importUnlabelledImages = new QCommandLineOption("import-unlabelled", "import images without labels"); importOverwrite = new QCommandLineOption("overwrite", "overwrite existing databases"); detectChannels = new QCommandLineOption("detect-channels", "number of channels", "detect-channels", "3"); detectTarget = new QCommandLineOption("detect-target", "Detection target", "CPU, CUDA", "CPU"); detectFramework = new QCommandLineOption("detect-framework", "Detection framework", "detect-framework", "Darknet"); detectConvertDepth = new QCommandLineOption("convert-depth", "Convert 16-bit to 8-bit"); detectGrayToRGB = new QCommandLineOption("convert-gray", "Convert RGB to grayscale"); detectNMSThresh = new QCommandLineOption("nms-thresh", "NMS Threshold", "threshold", "0.7"); detectConfThresh = new QCommandLineOption("conf-thresh", "Confidence Threshold", "threshold", "0.5"); detectConfig = new QCommandLineOption("config", "Path to model config file", "path"); detectWeights = new QCommandLineOption("weights", "Path to model weights file", "path"); configSilence = new QCommandLineOption({"q", "quiet"}, "no log messages"); parser.addHelpOption(); parser.addVersionOption(); parser.setOptionsAfterPositionalArgumentsMode(QCommandLineParser::ParseAsOptions); parser.addPositionalArgument("mode", "[export, import]"); parser.addOption(*exportFormatOption); parser.addOption(*exportOutputFolder); parser.addOption(*exportInputFile); parser.addOption(*exportValidationSplit); parser.addOption(*exportNoSubfolders); parser.addOption(*exportFilePrefix); parser.addOption(*exportNamesFile); parser.addOption(*exportGCPBucket); parser.addOption(*exportGCPLocal); parser.addOption(*exportPascalVOCLabelMap); parser.addOption(*exportShuffleImages); parser.addOption(*exportAppendLabels); parser.addOption(*exportVideoFourcc); parser.addOption(*exportVideoFps); parser.addOption(*exportVideoFilename); parser.addOption(*exportVideoColourmap); parser.addOption(*exportVideoSize); parser.addOption(*exportVideoDisplayBoxes); parser.addOption(*exportVideoDisplayNames); parser.addOption(*exportUnlabelledImages); parser.addOption(*importImages); parser.addOption(*importAnnotations); parser.addOption(*importRelativePath); parser.addOption(*importUnlabelledImages); parser.addOption(*importOverwrite); parser.addOption(*importTFRecordMask); parser.addOption(*detectChannels); parser.addOption(*detectTarget); parser.addOption(*detectFramework); parser.addOption(*detectConvertDepth); parser.addOption(*detectGrayToRGB); parser.addOption(*detectNMSThresh); parser.addOption(*detectConfThresh); parser.addOption(*detectConfig); parser.addOption(*detectWeights); parser.addOption(*configSilence); } bool CliParser::Run(){ parser.process(*QCoreApplication::instance()); bool res = false; auto mode = parser.positionalArguments().at(0); for(auto &option : parser.unknownOptionNames()){ qCritical() << "Unknown option: " << option; } if(parser.isSet(*configSilence)){ qSetMessagePattern(""); } if(mode == "export"){ res = handleExport(); }else if(mode == "import"){ res = handleImport(); }else if(mode == "merge"){ res = handleMerge(); }else if(mode == "detect"){ res = handleDetect(); } return res; } bool CliParser::handleDetect(){ DetectorOpenCV detector; qInfo() << "Using weights: " << parser.value("weights"); qInfo() << "Using config: " << parser.value("config"); detector.setChannels(parser.value("detect-channels").toInt()); detector.setTarget(parser.value("detect-target")); detector.setFramework(parser.value("detect-framework")); detector.setConvertGrayscale(parser.isSet("convert-gray")); detector.setConvertDepth(parser.isSet("convert-depth")); detector.setNMSThreshold(parser.value("nms-thresh").toDouble()); detector.setConfidenceThreshold(parser.value("conf-thresh").toDouble()); detector.loadNetwork(parser.value("names").toStdString(), parser.value("config").toStdString(), parser.value("weights").toStdString()); LabelProject project; project.loadDatabase(parser.value("input")); detector.runOnProject(&project); return true; } bool CliParser::handleMerge(){ qCritical() << "Not implemented yet"; return false; } bool CliParser::handleImport(){ QString database = parser.value("input"); LabelProject project; if(QFileInfo(database).exists()){ if(!parser.isSet("overwrite")){ qCritical() << "Database exists, will not ovewrite."; return false; } }else{ project.createDatabase(database); } project.loadDatabase(database); QThread* import_thread = new QThread; bool import_unlabelled = parser.isSet(*importUnlabelledImages); if(parser.value("format") == "darknet"){ if(!QFileInfo(parser.value("images")).exists()){ qCritical() << "Image list doesn't exist"; return false; } if(!QFileInfo(parser.value("names")).exists()){ qCritical() << "Names file doesn't exist"; return false; } DarknetImporter importer(&project); importer.moveToThread(import_thread); importer.setImportUnlabelled(import_unlabelled); if (parser.isSet("relative-path")) { importer.import(parser.value("images"), parser.value("names"), parser.value("relative-path")); } else { importer.import(parser.value("images"), parser.value("names")); } }else if(parser.value("format") == "coco"){ if(!QFileInfo(parser.value("annotations")).exists()){ qCritical() << "Image sequence folder doesn't exist"; return false; } CocoImporter importer(&project); importer.moveToThread(import_thread); importer.setImportUnlabelled(import_unlabelled); importer.import(parser.value("annotations"), parser.value("images")); }else if(parser.value("format") == "mot"){ if(!QDir(parser.value("images")).exists()){ qCritical() << "Image sequence folder doesn't exist"; return false; } if(!QFileInfo(parser.value("names")).exists()){ qCritical() << "Names file doesn't exist"; return false; } MOTImporter importer(&project); importer.moveToThread(import_thread); importer.setImportUnlabelled(import_unlabelled); importer.loadClasses(parser.value("names")); importer.import(parser.value("images")); }else if(parser.value("format") == "birdsai"){ if(!QDir(parser.value("annotations")).exists()){ qCritical() << "Annotations folder doesn't exist"; return false; } if(!QDir(parser.value("images")).exists()){ qCritical() << "Image sequence folder doesn't exist"; return false; } BirdsAIImporter importer(&project); importer.moveToThread(import_thread); importer.setImportUnlabelled(import_unlabelled); importer.loadClasses(parser.value("names")); importer.import(parser.value("images"), parser.value("annotations")); }else if(parser.value("format") == "tfrecord"){ TFRecordImporter importer(&project); importer.moveToThread(import_thread); importer.setImportUnlabelled(import_unlabelled); importer.import_records(parser.value("records")); }else if(parser.value("format") == "pascalvoc"){ PascalVOCImporter importer(&project); importer.moveToThread(import_thread); importer.setImportUnlabelled(import_unlabelled); importer.import(parser.value("images"), parser.value("annotations")); } return true; } bool CliParser::handleExport(){ QThread* export_thread = new QThread; BaseExporter* exporter = nullptr; LabelProject project; QString database = parser.value("input"); if(!QFileInfo(database).exists()){ qCritical() << "Database file does not exist."; return false; } if(!parser.isSet("input") || parser.value("input") == ""){ qCritical() << "No input file specified"; return false; }else{ qInfo() << "Attemting to load: " << parser.value("input"); project.loadDatabase(parser.value("input")); } if(parser.value(*exportFormatOption) == "kitti"){ exporter = new KittiExporter(&project); }else if(parser.value(*exportFormatOption) == "darknet"){ exporter = new DarknetExporter(&project); if(parser.isSet(*exportNamesFile)){ static_cast(exporter)->generateLabelIds(parser.value(*exportNamesFile)); }else{ qCritical() << "No names file specifed."; return false; } }else if(parser.value(*exportFormatOption) == "voc"){ exporter = new PascalVocExporter(&project); if(parser.isSet(*exportPascalVOCLabelMap)){ static_cast(exporter)->setExportMap(true); } exporter->process(); }else if(parser.value(*exportFormatOption) == "coco"){ exporter = new CocoExporter(&project); }else if(parser.value(*exportFormatOption) == "gcp"){ exporter = new GCPExporter(&project); if(parser.isSet(*exportGCPLocal)){ bool local = true; static_cast(exporter)->setBucket("", local); }else if(parser.isSet(*exportGCPBucket)){ static_cast(exporter)->setBucket(parser.value(*exportGCPBucket)); }else{ qCritical() << "Using bucket and no path specifed."; return false; } }else if(parser.value(*exportFormatOption) == "tfrecord"){ exporter = new TFRecordExporter(&project); if(parser.isSet(*exportNamesFile)){ static_cast(exporter)->generateLabelIds(parser.value(*exportNamesFile)); }else{ qCritical() << "No names file specifed."; return false; } }else if(parser.value(*exportFormatOption) == "video"){ exporter = new VideoExporter(&project); auto filename = parser.value(*exportVideoFilename); auto fourcc = parser.value(*exportVideoFourcc); bool ok = false; auto fps = parser.value(*exportVideoFps).toDouble(&ok); if(!ok){ qCritical() << "Invalid FPS, you specified: " << parser.value(*exportVideoFps); return false; } // Check video size auto videosize = parser.value(*exportVideoSize).split(","); if(videosize.size() != 2){ qCritical() << "Video size should be two comma separated values: w,h"; return false; } auto width = parser.value(*exportVideoSize).split(",").at(0).toInt(&ok); if(!ok){ qCritical() << "Invalid video width, you specified: " << parser.value(*exportVideoSize).split(",").at(0); return false; } auto height = parser.value(*exportVideoSize).split(",").at(1).toInt(&ok); if(!ok){ qCritical() << "Invalid video height, you specified: " << parser.value(*exportVideoSize).split(",").at(1); return false; } auto colourmap = parser.value(*exportVideoColourmap); static_cast(exporter)->videoConfig(filename, fourcc, fps, {width, height}, colourmap); static_cast(exporter)->labelConfig(parser.value(*exportVideoDisplayNames) == "on", parser.value(*exportVideoDisplayBoxes) == "on"); if(!parser.isSet(*exportOutputFolder) || parser.value(*exportOutputFolder) == ""){ qCritical() << "Please specify an output folder"; return false; }else{ exporter->setOutputFolder(parser.value(*exportOutputFolder), true); } exporter->process(); return true; }else{ qCritical() << "Invalid exporter type specified"; return false; } if(exporter != nullptr){ exporter->moveToThread(export_thread); // No progress bar exporter->disableProgress(true); exporter->setExportUnlabelled(parser.isSet(*exportUnlabelledImages)); if(parser.isSet(*exportFilePrefix)){ exporter->setFilenamePrefix(parser.value(*exportFilePrefix)); } exporter->setAppendLabels(parser.isSet(*exportAppendLabels)); if(parser.isSet(*exportValidationSplit)){ exporter->setValidationSplit(true); exporter->splitData(parser.value(*exportValidationSplit).toFloat(), parser.isSet(*exportShuffleImages)); }else{ exporter->setValidationSplit(false); exporter->splitData(0, parser.isSet(*exportShuffleImages)); } if(!parser.isSet(*exportOutputFolder) || parser.value(*exportOutputFolder) == ""){ qCritical() << "Please specify an output folder"; return false; }else{ exporter->setOutputFolder(parser.value(*exportOutputFolder), parser.isSet(*exportNoSubfolders)); } exporter->process(); }else{ qFatal("Failed to instantiate exporter"); return false; } return true; } ================================================ FILE: src/cliparser.h ================================================ #ifndef CLIPARSER_H #define CLIPARSER_H #include #include #include #include #include class CliParser : public QObject { Q_OBJECT public: explicit CliParser(QObject *parent = nullptr); bool Run(); private: void SetupOptions(); bool handleExport(); bool handleImport(); bool handleMerge(); bool handleDetect(); LabelProject getProject(bool &ok); QCommandLineParser parser; QCommandLineOption *exportFormatOption; QCommandLineOption *exportOutputFolder; QCommandLineOption *exportInputFile; QCommandLineOption *exportValidationSplit; QCommandLineOption *exportNoSubfolders; QCommandLineOption *exportFilePrefix; QCommandLineOption *exportNamesFile; QCommandLineOption *exportGCPBucket; QCommandLineOption *exportGCPLocal; QCommandLineOption *exportPascalVOCLabelMap; QCommandLineOption *exportShuffleImages; QCommandLineOption *exportAppendLabels; QCommandLineOption *exportUnlabelledImages; QCommandLineOption *exportVideoFilename; QCommandLineOption *exportVideoFourcc; QCommandLineOption *exportVideoFps; QCommandLineOption *exportVideoColourmap; QCommandLineOption *exportVideoSize; QCommandLineOption *exportVideoDisplayNames; QCommandLineOption *exportVideoDisplayBoxes; QCommandLineOption *importImages; QCommandLineOption *importAnnotations; QCommandLineOption *importUnlabelledImages; QCommandLineOption *importOverwrite; QCommandLineOption *importTFRecordMask; QCommandLineOption *importRelativePath; QCommandLineOption *detectChannels; QCommandLineOption *detectTarget; QCommandLineOption *detectFramework; QCommandLineOption *detectConvertDepth; QCommandLineOption *detectGrayToRGB; QCommandLineOption *detectNMSThresh; QCommandLineOption *detectConfThresh; QCommandLineOption *detectConfig; QCommandLineOption *detectWeights; QCommandLineOption *configSilence; signals: }; #endif // CLIPARSER_H ================================================ FILE: src/cliprogressbar.h ================================================ #ifndef CLIPROGRESSBAR_H #define CLIPROGRESSBAR_H #include // Thanks to https://github.com/GregoryConrad/pBar class cliProgressBar { public: void update(double newProgress) { currentProgress = std::ceil(newProgress); amountOfFiller = (int)((currentProgress / neededProgress)*(double)pBarLength); } void print() { currUpdateVal %= pBarUpdater.length(); std::cout << "\r" //Bring cursor to start of line << firstPartOfpBar; //Print out first part of pBar for (int a = 0; a < amountOfFiller; a++) { //Print out current progress std::cout << pBarFiller; } std::cout << pBarUpdater[currUpdateVal]; for (int b = 0; b < pBarLength - amountOfFiller; b++) { //Print out spaces std::cout << " "; } std::cout << lastPartOfpBar //Print out last part of progress bar << " (" << (int)(100*(currentProgress/neededProgress)) << "%)" //This just prints out the percent << std::flush; currUpdateVal += 1; } std::string firstPartOfpBar = "[", //Change these at will (that is why I made them public) lastPartOfpBar = "]", pBarFiller = "|", pBarUpdater = "/-\\|"; private: int amountOfFiller, pBarLength = 50, //I would recommend NOT changing this currUpdateVal = 0; //Do not change double currentProgress = 0, //Do not change neededProgress = 100; //I would recommend NOT changing this }; #endif // CLIPROGRESSBAR_H ================================================ FILE: src/cocoexporter.cpp ================================================ #include "cocoexporter.h" bool CocoExporter::processImages(const QString folder, const QString label_filename, const QList images){ QString image_path; QList labels; auto now = QDateTime::currentDateTime(); QJsonObject label_file; QJsonObject label_info; label_info["year"] = now.date().year(); label_info["version"] = "1"; label_info["description"] = "Description"; label_info["contributor"] = "Contributor"; label_info["date_created"] = now.date().toString(Qt::ISODate); label_info["url"] = ""; label_file["info"] = label_info; QJsonArray annotations_array; QJsonArray licenses_array; QJsonArray image_array; QJsonArray category_array; QList classnames; project->getClassList(classnames); for(auto &classname : classnames){ QJsonObject category; category["id"] = project->getClassId(classname); category["name"] = classname; category["supercategory"] = classname; category_array.append(category); } QProgressDialog progress("...", "Abort", 0, images.size(), static_cast(parent())); progress.setWindowModality(Qt::WindowModal); progress.setWindowTitle("Exporting images"); if(disable_progress){ progress.hide(); } int i = 0; foreach(image_path, images){ if(progress.wasCanceled()) break; project->getLabels(image_path, labels); if(!export_unlabelled && labels.size() == 0){ if(!disable_progress){ progress.setValue(i); progress.setLabelText(QString("%1 is unlabelled").arg(image_path)); progress.repaint(); QApplication::processEvents(); } continue; } QString abs_image_path = project->getDbFolder().absoluteFilePath(image_path); QString extension = QFileInfo(image_path).suffix(); QString filename_noext = QFileInfo(image_path).completeBaseName(); QString image_filename = QString("%1/%2%3.%4") .arg(folder) .arg(filename_prefix) .arg(filename_noext) .arg(extension); // Correct for duplicate file names in output int dupe_file = 1; while(QFile(image_filename).exists()){ image_filename = QString("%1/%2%3_%4.%5") .arg(folder) .arg(filename_prefix) .arg(filename_noext) .arg(dupe_file++) .arg(extension); } cv::Mat image = cv::imread(abs_image_path.toStdString()); //saveImage(image, image_filename); if(image.empty()){ qWarning() << "Failed top open image" << abs_image_path; continue; } auto copied = QFile::copy(abs_image_path, image_filename); if(!copied){ qWarning() << "Failed to copy image" << image_filename; } QJsonObject image_info; image_info["id"] = image_id; image_info["width"] = image.cols; image_info["height"] = image.rows; image_info["file_name"] = image_filename; image_info["license"] = 0; image_info["flickr_url"] = ""; image_info["coco_url"] = ""; image_info["date_captured"] = now.date().toString(Qt::ISODate); image_array.append(image_info); for(auto &label : labels){ QJsonObject annotation; annotation["id"] = label_id; annotation["image_id"] = image_id; annotation["category_id"] = label.classid; QJsonArray segmentation; segmentation.append(QString::number(label.rect.topLeft().x())); segmentation.append(QString::number(label.rect.topLeft().y())); segmentation.append(QString::number(label.rect.topRight().x())); segmentation.append(QString::number(label.rect.topRight().y())); segmentation.append(QString::number(label.rect.bottomRight().x())); segmentation.append(QString::number(label.rect.bottomRight().y())); segmentation.append(QString::number(label.rect.bottomLeft().x())); segmentation.append(QString::number(label.rect.bottomLeft().y())); QJsonArray segmentation_array; segmentation_array.append(segmentation); annotation["segmentation"] = segmentation_array; annotation["area"] = label.rect.width()*label.rect.height(); QJsonArray bbox; bbox.append(QString::number(label.rect.x())); bbox.append(QString::number(label.rect.y())); bbox.append(QString::number(label.rect.width())); bbox.append(QString::number(label.rect.height())); annotation["bbox"] = bbox; annotation["iscrowd"] = 0; annotations_array.append(annotation); label_id++; } image_id++; if(!disable_progress){ progress.setValue(++i); progress.setLabelText(image_path); } } QJsonObject license; license["id"] = 0; license["name"] = ""; license["url"] = ""; licenses_array.append(license); label_file["images"] = image_array; label_file["annotations"] = annotations_array; label_file["license"] = licenses_array; label_file["categories"] = category_array; QString label_filepath = QString("%1/%2.json").arg(output_folder).arg(label_filename); QJsonDocument json_output(label_file); QFile f(label_filepath); f.open(QIODevice::WriteOnly | QIODevice::Truncate); if(f.isOpen()){ f.write(json_output.toJson()); } f.close(); return true; } void CocoExporter::process(){ image_id = 0; label_id = 0; processImages(train_folder, "train", train_set); processImages(val_folder, "val", validation_set); } ================================================ FILE: src/cocoexporter.h ================================================ #ifndef COCOEXPORTER_H #define COCOEXPORTER_H #include #include #include #include class CocoExporter : public BaseExporter { Q_OBJECT public: explicit CocoExporter(LabelProject *project, QObject *parent = nullptr) : BaseExporter(project, parent){} public slots: void process(); private: bool processImages(const QString folder, const QString filename, const QList images); }; #endif // COCOEXPORTER_H ================================================ FILE: src/cocoimporter.cpp ================================================ #include "cocoimporter.h" void CocoImporter::import(QString annotation_file, QString image_folder){ // Load Json qDebug() << "Loading COCO JSON"; QFile loadFile(annotation_file); loadFile.open(QIODevice::ReadOnly | QIODevice::Text); QByteArray json_data = loadFile.readAll(); auto json = QJsonDocument::fromJson(json_data); // Load classes (categories) auto categories = json.object().value("categories"); if(categories == QJsonValue::Undefined){ qCritical() << "Categories not found"; return; } QMap classes; QSet class_set; QJsonValue item; foreach(item, categories.toArray()){ auto item_name = item.toObject().value("name"); if(item_name == QJsonValue::Undefined || !item_name.isString()) continue; auto item_id = item.toObject().value("id"); if(item_id == QJsonValue::Undefined || !item_id.isDouble()) continue; classes.insert(item_id.toInt(), item_name.toString()); qDebug() << "added: " << item_id.toInt() << " " << item_name.toString(); class_set.insert(item_name.toString()); } for(auto &cls : class_set){ project->addClass(cls); } // Load images auto images = json.object().value("images"); if(images == QJsonValue::Undefined){ qCritical() << "No images found"; return; } QJsonValue image; QList image_list; QList> label_list; QMap image_index; QMap image_map; int i=0; foreach(image, images.toArray()){ auto file_name = image.toObject().value("file_name"); if(file_name == QJsonValue::Undefined || !file_name.isString()) continue; auto file_id = image.toObject().value("id"); if(file_id == QJsonValue::Undefined || !file_id.isDouble()) continue; auto abs_file_name = QDir(image_folder).absoluteFilePath(file_name.toString()); image_map.insert(file_id.toInt(), abs_file_name); image_list.append(abs_file_name); label_list.append(QList {}); image_index.insert(file_id.toInt(), i++); } // Load labels auto annotations = json.object().value("annotations"); if(annotations == QJsonValue::Undefined){ qCritical() << "No annotations found"; return; } QJsonValue annotation; foreach(annotation, annotations.toArray()){ auto image_id = annotation.toObject().value("image_id"); if(image_id == QJsonValue::Undefined || !image_id.isDouble()) continue; auto category_id = annotation.toObject().value("category_id"); if(category_id == QJsonValue::Undefined || !category_id.isDouble()) continue; auto image_filename = image_map[image_id.toInt()]; auto bbox = annotation.toObject().value("bbox"); if(bbox == QJsonValue::Undefined || !bbox.isArray()){ qWarning() << "No bounding box found for" << image_id; continue; } auto bbox_array = bbox.toArray(); if(bbox_array.size() != 4) continue; int x = static_cast(bbox_array.at(0).toDouble()); int y = static_cast(bbox_array.at(1).toDouble()); int w = static_cast(bbox_array.at(2).toDouble()); int h = static_cast(bbox_array.at(3).toDouble()); if(w == 0){ qWarning() << "Bounding box for" << image_filename << "has zero width"; continue; } if(h == 0){ qWarning() << "Bounding box for" << image_filename << "has zero height"; continue; } BoundingBox new_bbox; new_bbox.rect.setX(x); new_bbox.rect.setY(y); new_bbox.rect.setWidth(w); new_bbox.rect.setHeight(h); int cat_id = static_cast(category_id.toDouble()); new_bbox.classname = classes[cat_id]; new_bbox.classid = project->getClassId(new_bbox.classname); label_list[image_index[image_id.toInt()]].push_back(new_bbox); } project->addLabelledAssets(image_list, label_list); return; } ================================================ FILE: src/cocoimporter.h ================================================ #ifndef COCOIMPORTER_H #define COCOIMPORTER_H #include #include #include #include class CocoImporter : public BaseImporter { public: using BaseImporter::import; explicit CocoImporter(LabelProject *project, QObject *parent = nullptr) : BaseImporter(parent){ this->project = project; } void import(QString annotations_file, QString image_folder); }; #endif // COCOIMPORTER_H ================================================ FILE: src/crc32.cpp ================================================ #include "crc32.h" #include namespace tf_crc{ static const uint32_t table0_[256] = { 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb, 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b, 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, 0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b, 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384, 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b, 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a, 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35, 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5, 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa, 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a, 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a, 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48, 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957, 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198, 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927, 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8, 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7, 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789, 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859, 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9, 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6, 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829, 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c, 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, 0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043, 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c, 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc, 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c, 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652, 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d, 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982, 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d, 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2, 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed, 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f, 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff, 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f, 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540, 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f, 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee, 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321, 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e, 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e, 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e, 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351}; static const uint32_t table1_[256] = { 0x00000000, 0x13a29877, 0x274530ee, 0x34e7a899, 0x4e8a61dc, 0x5d28f9ab, 0x69cf5132, 0x7a6dc945, 0x9d14c3b8, 0x8eb65bcf, 0xba51f356, 0xa9f36b21, 0xd39ea264, 0xc03c3a13, 0xf4db928a, 0xe7790afd, 0x3fc5f181, 0x2c6769f6, 0x1880c16f, 0x0b225918, 0x714f905d, 0x62ed082a, 0x560aa0b3, 0x45a838c4, 0xa2d13239, 0xb173aa4e, 0x859402d7, 0x96369aa0, 0xec5b53e5, 0xfff9cb92, 0xcb1e630b, 0xd8bcfb7c, 0x7f8be302, 0x6c297b75, 0x58ced3ec, 0x4b6c4b9b, 0x310182de, 0x22a31aa9, 0x1644b230, 0x05e62a47, 0xe29f20ba, 0xf13db8cd, 0xc5da1054, 0xd6788823, 0xac154166, 0xbfb7d911, 0x8b507188, 0x98f2e9ff, 0x404e1283, 0x53ec8af4, 0x670b226d, 0x74a9ba1a, 0x0ec4735f, 0x1d66eb28, 0x298143b1, 0x3a23dbc6, 0xdd5ad13b, 0xcef8494c, 0xfa1fe1d5, 0xe9bd79a2, 0x93d0b0e7, 0x80722890, 0xb4958009, 0xa737187e, 0xff17c604, 0xecb55e73, 0xd852f6ea, 0xcbf06e9d, 0xb19da7d8, 0xa23f3faf, 0x96d89736, 0x857a0f41, 0x620305bc, 0x71a19dcb, 0x45463552, 0x56e4ad25, 0x2c896460, 0x3f2bfc17, 0x0bcc548e, 0x186eccf9, 0xc0d23785, 0xd370aff2, 0xe797076b, 0xf4359f1c, 0x8e585659, 0x9dface2e, 0xa91d66b7, 0xbabffec0, 0x5dc6f43d, 0x4e646c4a, 0x7a83c4d3, 0x69215ca4, 0x134c95e1, 0x00ee0d96, 0x3409a50f, 0x27ab3d78, 0x809c2506, 0x933ebd71, 0xa7d915e8, 0xb47b8d9f, 0xce1644da, 0xddb4dcad, 0xe9537434, 0xfaf1ec43, 0x1d88e6be, 0x0e2a7ec9, 0x3acdd650, 0x296f4e27, 0x53028762, 0x40a01f15, 0x7447b78c, 0x67e52ffb, 0xbf59d487, 0xacfb4cf0, 0x981ce469, 0x8bbe7c1e, 0xf1d3b55b, 0xe2712d2c, 0xd69685b5, 0xc5341dc2, 0x224d173f, 0x31ef8f48, 0x050827d1, 0x16aabfa6, 0x6cc776e3, 0x7f65ee94, 0x4b82460d, 0x5820de7a, 0xfbc3faf9, 0xe861628e, 0xdc86ca17, 0xcf245260, 0xb5499b25, 0xa6eb0352, 0x920cabcb, 0x81ae33bc, 0x66d73941, 0x7575a136, 0x419209af, 0x523091d8, 0x285d589d, 0x3bffc0ea, 0x0f186873, 0x1cbaf004, 0xc4060b78, 0xd7a4930f, 0xe3433b96, 0xf0e1a3e1, 0x8a8c6aa4, 0x992ef2d3, 0xadc95a4a, 0xbe6bc23d, 0x5912c8c0, 0x4ab050b7, 0x7e57f82e, 0x6df56059, 0x1798a91c, 0x043a316b, 0x30dd99f2, 0x237f0185, 0x844819fb, 0x97ea818c, 0xa30d2915, 0xb0afb162, 0xcac27827, 0xd960e050, 0xed8748c9, 0xfe25d0be, 0x195cda43, 0x0afe4234, 0x3e19eaad, 0x2dbb72da, 0x57d6bb9f, 0x447423e8, 0x70938b71, 0x63311306, 0xbb8de87a, 0xa82f700d, 0x9cc8d894, 0x8f6a40e3, 0xf50789a6, 0xe6a511d1, 0xd242b948, 0xc1e0213f, 0x26992bc2, 0x353bb3b5, 0x01dc1b2c, 0x127e835b, 0x68134a1e, 0x7bb1d269, 0x4f567af0, 0x5cf4e287, 0x04d43cfd, 0x1776a48a, 0x23910c13, 0x30339464, 0x4a5e5d21, 0x59fcc556, 0x6d1b6dcf, 0x7eb9f5b8, 0x99c0ff45, 0x8a626732, 0xbe85cfab, 0xad2757dc, 0xd74a9e99, 0xc4e806ee, 0xf00fae77, 0xe3ad3600, 0x3b11cd7c, 0x28b3550b, 0x1c54fd92, 0x0ff665e5, 0x759baca0, 0x663934d7, 0x52de9c4e, 0x417c0439, 0xa6050ec4, 0xb5a796b3, 0x81403e2a, 0x92e2a65d, 0xe88f6f18, 0xfb2df76f, 0xcfca5ff6, 0xdc68c781, 0x7b5fdfff, 0x68fd4788, 0x5c1aef11, 0x4fb87766, 0x35d5be23, 0x26772654, 0x12908ecd, 0x013216ba, 0xe64b1c47, 0xf5e98430, 0xc10e2ca9, 0xd2acb4de, 0xa8c17d9b, 0xbb63e5ec, 0x8f844d75, 0x9c26d502, 0x449a2e7e, 0x5738b609, 0x63df1e90, 0x707d86e7, 0x0a104fa2, 0x19b2d7d5, 0x2d557f4c, 0x3ef7e73b, 0xd98eedc6, 0xca2c75b1, 0xfecbdd28, 0xed69455f, 0x97048c1a, 0x84a6146d, 0xb041bcf4, 0xa3e32483}; static const uint32_t table2_[256] = { 0x00000000, 0xa541927e, 0x4f6f520d, 0xea2ec073, 0x9edea41a, 0x3b9f3664, 0xd1b1f617, 0x74f06469, 0x38513ec5, 0x9d10acbb, 0x773e6cc8, 0xd27ffeb6, 0xa68f9adf, 0x03ce08a1, 0xe9e0c8d2, 0x4ca15aac, 0x70a27d8a, 0xd5e3eff4, 0x3fcd2f87, 0x9a8cbdf9, 0xee7cd990, 0x4b3d4bee, 0xa1138b9d, 0x045219e3, 0x48f3434f, 0xedb2d131, 0x079c1142, 0xa2dd833c, 0xd62de755, 0x736c752b, 0x9942b558, 0x3c032726, 0xe144fb14, 0x4405696a, 0xae2ba919, 0x0b6a3b67, 0x7f9a5f0e, 0xdadbcd70, 0x30f50d03, 0x95b49f7d, 0xd915c5d1, 0x7c5457af, 0x967a97dc, 0x333b05a2, 0x47cb61cb, 0xe28af3b5, 0x08a433c6, 0xade5a1b8, 0x91e6869e, 0x34a714e0, 0xde89d493, 0x7bc846ed, 0x0f382284, 0xaa79b0fa, 0x40577089, 0xe516e2f7, 0xa9b7b85b, 0x0cf62a25, 0xe6d8ea56, 0x43997828, 0x37691c41, 0x92288e3f, 0x78064e4c, 0xdd47dc32, 0xc76580d9, 0x622412a7, 0x880ad2d4, 0x2d4b40aa, 0x59bb24c3, 0xfcfab6bd, 0x16d476ce, 0xb395e4b0, 0xff34be1c, 0x5a752c62, 0xb05bec11, 0x151a7e6f, 0x61ea1a06, 0xc4ab8878, 0x2e85480b, 0x8bc4da75, 0xb7c7fd53, 0x12866f2d, 0xf8a8af5e, 0x5de93d20, 0x29195949, 0x8c58cb37, 0x66760b44, 0xc337993a, 0x8f96c396, 0x2ad751e8, 0xc0f9919b, 0x65b803e5, 0x1148678c, 0xb409f5f2, 0x5e273581, 0xfb66a7ff, 0x26217bcd, 0x8360e9b3, 0x694e29c0, 0xcc0fbbbe, 0xb8ffdfd7, 0x1dbe4da9, 0xf7908dda, 0x52d11fa4, 0x1e704508, 0xbb31d776, 0x511f1705, 0xf45e857b, 0x80aee112, 0x25ef736c, 0xcfc1b31f, 0x6a802161, 0x56830647, 0xf3c29439, 0x19ec544a, 0xbcadc634, 0xc85da25d, 0x6d1c3023, 0x8732f050, 0x2273622e, 0x6ed23882, 0xcb93aafc, 0x21bd6a8f, 0x84fcf8f1, 0xf00c9c98, 0x554d0ee6, 0xbf63ce95, 0x1a225ceb, 0x8b277743, 0x2e66e53d, 0xc448254e, 0x6109b730, 0x15f9d359, 0xb0b84127, 0x5a968154, 0xffd7132a, 0xb3764986, 0x1637dbf8, 0xfc191b8b, 0x595889f5, 0x2da8ed9c, 0x88e97fe2, 0x62c7bf91, 0xc7862def, 0xfb850ac9, 0x5ec498b7, 0xb4ea58c4, 0x11abcaba, 0x655baed3, 0xc01a3cad, 0x2a34fcde, 0x8f756ea0, 0xc3d4340c, 0x6695a672, 0x8cbb6601, 0x29faf47f, 0x5d0a9016, 0xf84b0268, 0x1265c21b, 0xb7245065, 0x6a638c57, 0xcf221e29, 0x250cde5a, 0x804d4c24, 0xf4bd284d, 0x51fcba33, 0xbbd27a40, 0x1e93e83e, 0x5232b292, 0xf77320ec, 0x1d5de09f, 0xb81c72e1, 0xccec1688, 0x69ad84f6, 0x83834485, 0x26c2d6fb, 0x1ac1f1dd, 0xbf8063a3, 0x55aea3d0, 0xf0ef31ae, 0x841f55c7, 0x215ec7b9, 0xcb7007ca, 0x6e3195b4, 0x2290cf18, 0x87d15d66, 0x6dff9d15, 0xc8be0f6b, 0xbc4e6b02, 0x190ff97c, 0xf321390f, 0x5660ab71, 0x4c42f79a, 0xe90365e4, 0x032da597, 0xa66c37e9, 0xd29c5380, 0x77ddc1fe, 0x9df3018d, 0x38b293f3, 0x7413c95f, 0xd1525b21, 0x3b7c9b52, 0x9e3d092c, 0xeacd6d45, 0x4f8cff3b, 0xa5a23f48, 0x00e3ad36, 0x3ce08a10, 0x99a1186e, 0x738fd81d, 0xd6ce4a63, 0xa23e2e0a, 0x077fbc74, 0xed517c07, 0x4810ee79, 0x04b1b4d5, 0xa1f026ab, 0x4bdee6d8, 0xee9f74a6, 0x9a6f10cf, 0x3f2e82b1, 0xd50042c2, 0x7041d0bc, 0xad060c8e, 0x08479ef0, 0xe2695e83, 0x4728ccfd, 0x33d8a894, 0x96993aea, 0x7cb7fa99, 0xd9f668e7, 0x9557324b, 0x3016a035, 0xda386046, 0x7f79f238, 0x0b899651, 0xaec8042f, 0x44e6c45c, 0xe1a75622, 0xdda47104, 0x78e5e37a, 0x92cb2309, 0x378ab177, 0x437ad51e, 0xe63b4760, 0x0c158713, 0xa954156d, 0xe5f54fc1, 0x40b4ddbf, 0xaa9a1dcc, 0x0fdb8fb2, 0x7b2bebdb, 0xde6a79a5, 0x3444b9d6, 0x91052ba8}; static const uint32_t table3_[256] = { 0x00000000, 0xdd45aab8, 0xbf672381, 0x62228939, 0x7b2231f3, 0xa6679b4b, 0xc4451272, 0x1900b8ca, 0xf64463e6, 0x2b01c95e, 0x49234067, 0x9466eadf, 0x8d665215, 0x5023f8ad, 0x32017194, 0xef44db2c, 0xe964b13d, 0x34211b85, 0x560392bc, 0x8b463804, 0x924680ce, 0x4f032a76, 0x2d21a34f, 0xf06409f7, 0x1f20d2db, 0xc2657863, 0xa047f15a, 0x7d025be2, 0x6402e328, 0xb9474990, 0xdb65c0a9, 0x06206a11, 0xd725148b, 0x0a60be33, 0x6842370a, 0xb5079db2, 0xac072578, 0x71428fc0, 0x136006f9, 0xce25ac41, 0x2161776d, 0xfc24ddd5, 0x9e0654ec, 0x4343fe54, 0x5a43469e, 0x8706ec26, 0xe524651f, 0x3861cfa7, 0x3e41a5b6, 0xe3040f0e, 0x81268637, 0x5c632c8f, 0x45639445, 0x98263efd, 0xfa04b7c4, 0x27411d7c, 0xc805c650, 0x15406ce8, 0x7762e5d1, 0xaa274f69, 0xb327f7a3, 0x6e625d1b, 0x0c40d422, 0xd1057e9a, 0xaba65fe7, 0x76e3f55f, 0x14c17c66, 0xc984d6de, 0xd0846e14, 0x0dc1c4ac, 0x6fe34d95, 0xb2a6e72d, 0x5de23c01, 0x80a796b9, 0xe2851f80, 0x3fc0b538, 0x26c00df2, 0xfb85a74a, 0x99a72e73, 0x44e284cb, 0x42c2eeda, 0x9f874462, 0xfda5cd5b, 0x20e067e3, 0x39e0df29, 0xe4a57591, 0x8687fca8, 0x5bc25610, 0xb4868d3c, 0x69c32784, 0x0be1aebd, 0xd6a40405, 0xcfa4bccf, 0x12e11677, 0x70c39f4e, 0xad8635f6, 0x7c834b6c, 0xa1c6e1d4, 0xc3e468ed, 0x1ea1c255, 0x07a17a9f, 0xdae4d027, 0xb8c6591e, 0x6583f3a6, 0x8ac7288a, 0x57828232, 0x35a00b0b, 0xe8e5a1b3, 0xf1e51979, 0x2ca0b3c1, 0x4e823af8, 0x93c79040, 0x95e7fa51, 0x48a250e9, 0x2a80d9d0, 0xf7c57368, 0xeec5cba2, 0x3380611a, 0x51a2e823, 0x8ce7429b, 0x63a399b7, 0xbee6330f, 0xdcc4ba36, 0x0181108e, 0x1881a844, 0xc5c402fc, 0xa7e68bc5, 0x7aa3217d, 0x52a0c93f, 0x8fe56387, 0xedc7eabe, 0x30824006, 0x2982f8cc, 0xf4c75274, 0x96e5db4d, 0x4ba071f5, 0xa4e4aad9, 0x79a10061, 0x1b838958, 0xc6c623e0, 0xdfc69b2a, 0x02833192, 0x60a1b8ab, 0xbde41213, 0xbbc47802, 0x6681d2ba, 0x04a35b83, 0xd9e6f13b, 0xc0e649f1, 0x1da3e349, 0x7f816a70, 0xa2c4c0c8, 0x4d801be4, 0x90c5b15c, 0xf2e73865, 0x2fa292dd, 0x36a22a17, 0xebe780af, 0x89c50996, 0x5480a32e, 0x8585ddb4, 0x58c0770c, 0x3ae2fe35, 0xe7a7548d, 0xfea7ec47, 0x23e246ff, 0x41c0cfc6, 0x9c85657e, 0x73c1be52, 0xae8414ea, 0xcca69dd3, 0x11e3376b, 0x08e38fa1, 0xd5a62519, 0xb784ac20, 0x6ac10698, 0x6ce16c89, 0xb1a4c631, 0xd3864f08, 0x0ec3e5b0, 0x17c35d7a, 0xca86f7c2, 0xa8a47efb, 0x75e1d443, 0x9aa50f6f, 0x47e0a5d7, 0x25c22cee, 0xf8878656, 0xe1873e9c, 0x3cc29424, 0x5ee01d1d, 0x83a5b7a5, 0xf90696d8, 0x24433c60, 0x4661b559, 0x9b241fe1, 0x8224a72b, 0x5f610d93, 0x3d4384aa, 0xe0062e12, 0x0f42f53e, 0xd2075f86, 0xb025d6bf, 0x6d607c07, 0x7460c4cd, 0xa9256e75, 0xcb07e74c, 0x16424df4, 0x106227e5, 0xcd278d5d, 0xaf050464, 0x7240aedc, 0x6b401616, 0xb605bcae, 0xd4273597, 0x09629f2f, 0xe6264403, 0x3b63eebb, 0x59416782, 0x8404cd3a, 0x9d0475f0, 0x4041df48, 0x22635671, 0xff26fcc9, 0x2e238253, 0xf36628eb, 0x9144a1d2, 0x4c010b6a, 0x5501b3a0, 0x88441918, 0xea669021, 0x37233a99, 0xd867e1b5, 0x05224b0d, 0x6700c234, 0xba45688c, 0xa345d046, 0x7e007afe, 0x1c22f3c7, 0xc167597f, 0xc747336e, 0x1a0299d6, 0x782010ef, 0xa565ba57, 0xbc65029d, 0x6120a825, 0x0302211c, 0xde478ba4, 0x31035088, 0xec46fa30, 0x8e647309, 0x5321d9b1, 0x4a21617b, 0x9764cbc3, 0xf54642fa, 0x2803e842}; // Used to fetch a naturally-aligned 32-bit word in little endian byte-order static inline uint32_t LE_LOAD32(const uint8_t *p) { // Taken from tensorflow/tensorflow/core/platform/raw_coding.h return ((static_cast(static_cast(p[0]))) | (static_cast(static_cast(p[1])) << 8) | (static_cast(static_cast(p[2])) << 16) | (static_cast(static_cast(p[3])) << 24)); } uint32_t Extend(uint32_t crc, const char *buf, size_t size) { const uint8_t *p = reinterpret_cast(buf); const uint8_t *e = p + size; uint32_t l = crc ^ 0xffffffffu; #define STEP1 \ do { \ int c = (l & 0xff) ^ *p++; \ l = table0_[c] ^ (l >> 8); \ } while (0) #define STEP4 \ do { \ uint32_t c = l ^ LE_LOAD32(p); \ p += 4; \ l = table3_[c & 0xff] ^ table2_[(c >> 8) & 0xff] ^ \ table1_[(c >> 16) & 0xff] ^ table0_[c >> 24]; \ } while (0) // Point x at first 4-byte aligned byte in string. This might be // just past the end of the string. const uintptr_t pval = reinterpret_cast(p); const uint8_t *x = reinterpret_cast(((pval + 3) >> 2) << 2); if (x <= e) { // Process bytes until finished or p is 4-byte aligned while (p != x) { STEP1; } } // Process bytes 16 at a time while ((e - p) >= 16) { STEP4; STEP4; STEP4; STEP4; } // Process bytes 4 at a time while ((e - p) >= 4) { STEP4; } // Process the last few bytes while (p != e) { STEP1; } #undef STEP4 #undef STEP1 return l ^ 0xffffffffu; } } ================================================ FILE: src/crc32.h ================================================ /* Copyright 2015 The TensorFlow Authors. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ #ifndef CRC32_H #define CRC32_H #include #include namespace tf_crc{ // Return the crc32c of concat(A, data[0,n-1]) where init_crc is the // crc32c of some string A. Extend() is often used to maintain the // crc32c of a stream of data. extern uint32_t Extend(uint32_t init_crc, const char* data, size_t n); // Return the crc32c of data[0,n-1] inline uint32_t Value(const char* data, size_t n) { return Extend(0, data, n); } #if defined(PLATFORM_GOOGLE) extern uint32_t Extend(uint32_t init_crc, const absl::Cord& cord); inline uint32_t Value(const absl::Cord& cord) { return Extend(0, cord); } #endif static const uint32_t kMaskDelta = 0xa282ead8ul; // Return a masked representation of crc. // // Motivation: it is problematic to compute the CRC of a string that // contains embedded CRCs. Therefore we recommend that CRCs stored // somewhere (e.g., in files) should be masked before being stored. inline uint32_t Mask(uint32_t crc) { // Rotate right by 15 bits and add a constant. return ((crc >> 15) | (crc << 17)) + kMaskDelta; } // Return the crc whose masked representation is masked_crc. inline uint32_t Unmask(uint32_t masked_crc) { uint32_t rot = masked_crc - kMaskDelta; return ((rot >> 17) | (rot << 15)); } } #endif // TENSORFLOW_CORE_LIB_HASH_CRC32C_H_ ================================================ FILE: src/darknetexporter.cpp ================================================ #include "darknetexporter.h" void DarknetExporter::generateLabelIds(const QString names_file){ id_map.clear(); // Force sort list QStringList class_list; QFile fh(names_file); if (fh.open(QIODevice::ReadOnly)) { while (!fh.atEnd()) { // Darknet name file is just a newline delimited list of classes QByteArray line = fh.readLine(); class_list.append(line); } } if(class_list.size() == 0){ qWarning() << "No classes found in names file."; return; } int i = 0; for(auto &name : class_list){ auto cleaned_name = name.simplified().toLower(); id_map[cleaned_name] = i++; qDebug() << "Adding: " << cleaned_name << " (" << i << ")"; } } double clamp(double val, double min, double max){ if(val < min) val = min; if(val > max) val = max; return val; } void DarknetExporter::writeLabels(const cv::Mat &image, const QString label_filename, const QList labels){ // Still make a label file even if there are no detections. This is important // for background class detection. QFile f(label_filename); // Delete existing files for simplicity. if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) { BoundingBox label; foreach(label, labels){ QString text; // Check if this label exists in the database if(id_map.find(label.classname.toLower()) == id_map.end()){ qWarning() << "Couldn't find this label in the names file: " << label.classname.toLower(); continue; } double x = clamp(static_cast(label.rect.center().x())/image.cols, 0.0, 0.999); double y = clamp(static_cast(label.rect.center().y())/image.rows, 0.0, 0.999); double width = clamp(static_cast(label.rect.width())/image.cols, 0.0, 0.999); double height = clamp(static_cast(label.rect.height())/image.rows, 0.0, 0.999); text += QString("%1").arg(id_map[label.classname.toLower()]); text += QString(" %1").arg(x); text += QString(" %1").arg(y); text += QString(" %1").arg(width); text += QString(" %1").arg(height); text += "\n"; f.write(text.toUtf8()); } } } bool DarknetExporter::processImages(const QString folder, const QList images, export_image_type split_type){ QString image_path; QList labels; QProgressDialog progress("...", "Abort", 0, images.size(), static_cast(parent())); progress.setWindowModality(Qt::WindowModal); if(folder == ""){ qCritical() << "Invalid folder specified."; return false; } QString split_text = ""; if(split_type == EXPORT_VAL){ split_text = "VAL"; progress.setWindowTitle("Exporting validation images"); }else if(split_type == EXPORT_TRAIN){ split_text = "TRAIN"; progress.setWindowTitle("Exporting train images"); }else if(split_type == EXPORT_TEST){ split_text = "TEST"; progress.setWindowTitle("Exporting test images"); }else{ split_text = "UNASSIGNED"; } if(!disable_progress){ progress.hide(); } int i = 0; foreach(image_path, images){ if(progress.wasCanceled()){ break; } project->getLabels(image_path, labels); if(!export_unlabelled && labels.size() == 0){ if(!disable_progress){ progress.setValue(i); progress.setLabelText(QString("%1 is unlabelled").arg(image_path)); progress.repaint(); QApplication::processEvents(); } qDebug() << image_path << "is unlabelled"; continue; }else{ qDebug() << "Processing:" << image_path; } QString extension = QFileInfo(image_path).suffix(); QString filename_noext = QFileInfo(image_path).completeBaseName(); filename_noext = filename_noext.prepend(filename_prefix); QString image_filename = QString("%1.%2").arg(filename_noext).arg(extension); QString label_filename = QString("%1.txt").arg(filename_noext); // Correct for duplicate file names in output int dupe_file = 1; while(QFile(image_filename).exists()){ image_filename = QString("%1%2.%3") .arg(filename_noext) .arg(dupe_file) .arg(extension); label_filename = QString("%1.txt").arg(filename_noext).arg(dupe_file); dupe_file++; } image_filename = QString("%1/%2").arg(folder).arg(image_filename); label_filename = QString("%1/%2").arg(folder).arg(label_filename); auto db_dir = project->getDbFolder(); auto abs_path = QFileInfo(QDir::cleanPath(db_dir.filePath(image_path))).absoluteFilePath(); qDebug() << "Copy:" << abs_path << " to: " << image_filename; auto copied = QFile::copy(abs_path, image_filename); if(!copied){ qWarning() << "Failed to copy image" << image_filename; } cv::Mat image = cv::imread(abs_path.toStdString()); if(image.empty()){ qCritical() << "Failed to load image!" << abs_path; }else{ writeLabels(image, label_filename, labels); } if(!disable_progress){ progress.setValue(i++); progress.setLabelText(image_filename); } } return true; } void DarknetExporter::process(){ processImages(train_folder, train_set, EXPORT_TRAIN); processImages(val_folder, validation_set, EXPORT_VAL); } ================================================ FILE: src/darknetexporter.h ================================================ #ifndef DARKNETEXPORTER_H #define DARKNETEXPORTER_H #include #include class DarknetExporter : public BaseExporter { Q_OBJECT public: explicit DarknetExporter(LabelProject *project, QObject *parent = nullptr) : BaseExporter(project, parent){} signals: void export_progress(int); public slots: void generateLabelIds(const QString names_file); void process(); protected: void writeLabels(const cv::Mat &image, const QString file, const QList labels); bool processImages(const QString folder, const QList images, export_image_type split_type=EXPORT_TRAIN); }; #endif // DARKNETEXPORTER_H ================================================ FILE: src/darknetimporter.cpp ================================================ #include "darknetimporter.h" void DarknetImporter::import(QString image_list, QString names_file, QString root_folder) { loadClasses(names_file); // Get image filenames auto filenames = readLines(image_list); filenames.sort(); QProgressDialog progress("...", "Abort", 0, filenames.size(), static_cast(parent())); progress.setWindowModality(Qt::WindowModal); progress.setWindowTitle("Loading images and labels"); int i = 0; QList> bboxes; if (root_folder != "") qInfo() << "Using relative pathnames, relative to: " << root_folder; for(auto &image_path : filenames){ if(progress.wasCanceled()) break; if (root_folder != "") { auto abs_path = QDir(root_folder).absoluteFilePath(image_path); if (!QFileInfo(abs_path).exists()) { qWarning() << "Image: " << abs_path << " doesn't exist. Check your root folder."; continue; } else { image_path = QFileInfo(abs_path).canonicalFilePath(); } } else { if (QFileInfo(image_path).isRelative()) { qWarning() << "Relative image path: " << image_path << " provided, but no root folder specified"; continue; } } bboxes.append(loadLabels(image_path)); progress.setValue(++i); progress.setLabelText(QString("%1/%2: %3").arg(i).arg(filenames.size()).arg(image_path)); } if(progress.wasCanceled()) project->addLabelledAssets(filenames.mid(0, bboxes.size()), bboxes); else project->addLabelledAssets(filenames, bboxes); } QList DarknetImporter::loadLabels(QString image_path){ QList boxes = {}; auto info = QFileInfo(image_path); QString filename_noext = QDir(info.absolutePath()).filePath(info.baseName()); QString label_filename = QString("%1.txt").arg(filename_noext); auto image = cv::imread(image_path.toStdString()); auto width = image.cols; auto height = image.rows; if(width <= 0 || height <= 0) return boxes; auto lines = readLines(label_filename); for(auto &line : lines){ BoundingBox bbox; auto label = line.simplified().split(" "); if(label.size() != 5) continue; bbox.classid = label.at(0).toInt() + 1; // Since in the database they're 1-indexed bbox.classname = project->getClassName(bbox.classid); if(bbox.classname == ""){ qWarning() << "Class" << bbox.classid << " not found in names file."; } int center_x = static_cast(label.at(1).toFloat() * width); int center_y = static_cast(label.at(2).toFloat() * height); int box_width = static_cast(label.at(3).toFloat() * width); int box_height = static_cast(label.at(4).toFloat() * height); auto top_left = QPoint(std::min(std::max(center_x - box_width/2, 0), width), std::min(std::max(center_y - box_height/2, 0), height)); auto bottom_right = QPoint(std::min(std::max(center_x + box_width/2, 0), width), std::min(std::max(center_y + box_height/2, 0), height)); bbox.rect = QRect(top_left, bottom_right); boxes.append(bbox); } return boxes; } void DarknetImporter::loadClasses(QString names_file){ QFile fh(names_file); if (fh.open(QIODevice::ReadOnly)) { while (!fh.atEnd()) { // Darknet name file is just a newline delimited list of classes QByteArray line = fh.readLine(); if(QString(line) == "") continue; project->addClass(line.simplified()); qInfo() << line.simplified(); } } } ================================================ FILE: src/darknetimporter.h ================================================ #ifndef DARKNETIMPORTER_H #define DARKNETIMPORTER_H #include class DarknetImporter : public BaseImporter { public: using BaseImporter::import; explicit DarknetImporter(LabelProject *project, QObject *parent = nullptr) : BaseImporter(parent){ this->project = project; } void import(QString image_list, QString names_file, QString root_folder = ""); private: void loadClasses(QString names_file); QList loadLabels(QString image); }; #endif // DARKNETIMPORTER_H ================================================ FILE: src/detection/detectoropencv.cpp ================================================ #include "detectoropencv.h" DetectorOpenCV::DetectorOpenCV() { } model_framework DetectorOpenCV::frameworkFromString(QString framework_string){ model_framework framework = FRAMEWORK_DARKNET; if(framework_string.toLower().startsWith("darknet")){ framework = FRAMEWORK_DARKNET; qInfo() << "Detector framework: Darknet"; }else if(framework_string.toLower().startsWith("tensorflow")){ framework = FRAMEWORK_TENSORFLOW; qInfo() << "Detector framework: Tensorflow"; } return framework; } int DetectorOpenCV::targetFromString(QString target_string){ int target = cv::dnn::DNN_TARGET_CPU; if(target_string == "CPU"){ target = cv::dnn::DNN_TARGET_CPU; }else if(target_string == "OpenCL"){ target = cv::dnn::DNN_TARGET_OPENCL; }else if(target_string == "OpenCL FP16"){ target = cv::dnn::DNN_TARGET_OPENCL_FP16; }else if(target_string == "CUDA"){ target = cv::dnn::DNN_TARGET_CUDA; }else if(target_string == "CUDA FP16"){ target = cv::dnn::DNN_TARGET_CUDA_FP16; } return target; } void DetectorOpenCV::setTarget(QString target){ setTarget(targetFromString(target)); } void DetectorOpenCV::setFramework(QString framework){ setFramework(frameworkFromString(framework)); } void DetectorOpenCV::setImageSize(int width, int height){ if(width > 0 && height > 0){ input_width = width; input_height = height; } } void DetectorOpenCV::readNamesFile(std::string class_file){ class_names.clear(); // Load names of classes std::ifstream ifs(class_file.c_str()); std::string line; int i=0; while (std::getline(ifs, line)){ QString cleaned = QString::fromStdString(line).simplified().toLower(); class_names.push_back(cleaned.toStdString()); std::cout << "Added detection class: " << i++ << " " << class_names.back() << std::endl; } } void DetectorOpenCV::setChannels(int channels){ input_channels = channels; } void DetectorOpenCV::setTarget(int target){ preferable_target = target; if(preferable_target == cv::dnn::DNN_TARGET_OPENCL){ // Check for GPU cv::ocl::Context context; if(!cv::ocl::haveOpenCL()){ std::cout << "OpenCL is not available. Falling back to CPU" << std::endl; preferable_target = cv::dnn::DNN_TARGET_CPU; } // Attempt to use a GPU if(context.create(cv::ocl::Device::TYPE_GPU)){ std::cout << "Found OpenCL capable GPU - we're going to use it!" << std::endl; cv::ocl::Device(context.device(1)); } } #ifdef WITH_CUDA else if(preferable_target == cv::dnn::DNN_TARGET_CUDA || preferable_target == cv::dnn::DNN_TARGET_CUDA_FP16){ try{ // Check for GPU if(cv::cuda::getCudaEnabledDeviceCount() == 0){ qCritical() << "No CUDA enabled devices found"; preferable_target = cv::dnn::DNN_TARGET_CPU; return; }else{ cv::cuda::setDevice(0); } auto devinfo = cv::cuda::DeviceInfo(); if (!devinfo.isCompatible()){ qWarning() << "Device is not CUDA compatible. Falling back to CPU"; preferable_target = cv::dnn::DNN_TARGET_CPU; }else{ qInfo() << "NVIDIA GPU detected: " << devinfo.name(); } }catch(...){ qCritical() << "Problem calling GPU functions, defaulting to CPU inference mode."; qCritical() << "Check that OpenCV was compiled with CUDA or try rebooting."; preferable_target = cv::dnn::DNN_TARGET_CPU; } } #endif } void DetectorOpenCV::loadNetwork(std::string names_file, std::string cfg_file, std::string model_file){ // Load the names readNamesFile(names_file); // Infer network type automatically net = cv::dnn::readNet(model_file, cfg_file); // Should default to DNN_BACKEND_OPENCV (otherwise Intel inference engine) if(preferable_target == cv::dnn::DNN_TARGET_CUDA || preferable_target == cv::dnn::DNN_TARGET_CUDA_FP16){ net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA); qDebug() << "Set preferable backend and target to CUDA"; }else{ net.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV); } net.setPreferableTarget(preferable_target); getOutputClassNames(); } void DetectorOpenCV::getOutputClassNames() { output_names.clear(); //Get the indices of the output layers, i.e. the layers with unconnected outputs std::vector outLayers = net.getUnconnectedOutLayers(); //get the names of all the layers in the network std::vector layersNames = net.getLayerNames(); // Get the names of the output layers in names output_names.resize(outLayers.size()); for (size_t i = 0; i < outLayers.size(); ++i){ output_names.at(i) = layersNames.at(static_cast(outLayers[i]) - 1); } } void DetectorOpenCV::postProcessTensorflow(cv::Mat& frame, const std::vector& outputs, std::vector &filtered_boxes){ std::vector classIds; std::vector confidences; std::vector boxes; auto detections = outputs.at(0); const int numDetections = detections.size[2]; std::cout << "Outputs_size: " << detections.total() << std::endl; std::cout << "Number of detections: " << numDetections << std::endl; // batch id, class id, confidence, bbox (x4) detections = detections.reshape(1, static_cast(detections.total()) / 7); // There are top-k (= 100 typical) detections, most of which should have // more or less zero confidence. for (int i = 0; i < numDetections; ++i) { float confidence = detections.at(i, 2); if (confidence > confThreshold) { // Extract the bounding box int classId = static_cast(detections.at(i, 1)); int left = static_cast(frame.cols * detections.at(i, 3)); int top = static_cast(frame.rows * detections.at(i, 4)); int right = static_cast(frame.cols * detections.at(i, 5)); int bottom = static_cast(frame.rows * detections.at(i, 6)); BoundingBox bbox; bbox.rect.setLeft(std::max(0, std::min(left, frame.cols - 1))); bbox.rect.setTop(std::max(0, std::min(top, frame.rows - 1))); bbox.rect.setRight(std::max(0, std::min(right, frame.cols - 1))); bbox.rect.setBottom(std::max(0, std::min(bottom, frame.rows - 1))); bbox.confidence = static_cast(confidence); bbox.classid = classId; bbox.classname = QString::fromStdString(class_names.at(static_cast(bbox.classid))); std::cout << "Found (" << bbox.classid << ") " << bbox.classname.toStdString() << " at" << " (" << bbox.rect.center().x() << ", " << bbox.rect.center().y() << "), conf: " << bbox.confidence << ", size (" << bbox.rect.width() << "x" << bbox.rect.height() << ")" << std::endl; filtered_boxes.push_back(bbox); }else{ // } } } void DetectorOpenCV::postProcess(cv::Mat& frame, const std::vector& outputs, std::vector &filtered_boxes) { std::vector classIds; std::vector confidences; std::vector boxes; // Debug: this should be three because there are three scales that Yolo searches over //std::cout << "Outputs: " << outputs.size() << std::endl; for (size_t i = 0; i < outputs.size(); ++i) { // Scan through all the bounding boxes output from the network and keep only the // ones with high confidence scores. Assign the box's class label as the class // with the highest score for the box. float* data = reinterpret_cast(outputs[i].data); for (int j = 0; j < outputs[i].rows; ++j, data += outputs[i].cols) { cv::Mat scores = outputs[i].row(j).colRange(5, outputs[i].cols); cv::Point classIdPoint; double confidence; // Get the value and location of the maximum score minMaxLoc(scores, nullptr, &confidence, nullptr, &classIdPoint); if (confidence > 0) { // Output is a percentage of the frame width/height // so it doesn't matter that we're transforming boxes // between the resized and full-size image. int centerX = static_cast(data[0] * frame.cols); int centerY = static_cast(data[1] * frame.rows); int width = static_cast(data[2] * frame.cols); int height = static_cast(data[3] * frame.rows); int left = centerX - width / 2; int top = centerY - height / 2; classIds.push_back(classIdPoint.x); confidences.push_back(static_cast(confidence)); boxes.push_back(cv::Rect(left, top, width, height)); }else{ if(confidence == 0.0) continue; std::cout << "Detected " << class_names.at(static_cast(classIdPoint.x)) << " with low confidence: " << confidence << std::endl; } } } std::vector indices; // Perform non maximum suppression to eliminate redundant overlapping boxes with // lower confidences // We set the confidence threshold to zero here, we'll filter the boxes out later. // This lets us provide some feedback to the user if their threshold is too high. cv::dnn::NMSBoxes(boxes, confidences, static_cast(confThreshold), static_cast(nmsThreshold), indices); for (size_t i = 0; i < indices.size(); ++i) { auto idx = static_cast(indices.at(i)); BoundingBox box; cv::Rect rect = boxes.at(idx); box.confidence = static_cast(confidences.at(idx)); box.classid = classIds.at(idx); box.classname = QString::fromStdString(class_names.at(static_cast(box.classid))); // Darknet predicts box centres and half-width/height, so the // box can go outside the image. Clamp to the image size: QPoint top_left = {std::max(0, rect.x), std::max(0, rect.y)}; QPoint bottom_right = top_left + QPoint({rect.width, rect.height}); bottom_right.setX(std::min(bottom_right.x(), frame.cols)); bottom_right.setY(std::min(bottom_right.y(), frame.rows)); box.rect.setBottomRight(bottom_right); box.rect.setTopLeft(top_left); std::cout << "Found " << box.classname.toStdString() << " at" << " (" << box.rect.center().x() << ", " << box.rect.center().y() << "), conf: " << box.confidence << ", size (" << box.rect.width() << "x" << box.rect.height() << ")" << std::endl; filtered_boxes.push_back(box); } return; } std::vector DetectorOpenCV::infer(cv::Mat image){ std::vector detections; // Assume we have an alpha image if 4 channels if(image.channels() == 4){ cv::cvtColor(image, image, cv::COLOR_BGRA2BGR); } // 16-bit conversion, min-max scaling if(convert_depth && image.elemSize() == 2){ double minval, maxval; cv::minMaxIdx(image, &minval, &maxval); double range = maxval-minval; double scale_factor = 255.0/range; image.convertTo(image, CV_32FC1); image -= minval; image *= scale_factor; image.convertTo(image, CV_8UC1); } if(convert_grayscale && image.channels() == 1){ cv::cvtColor(image, image, cv::COLOR_GRAY2RGB); } if(image.channels() != input_channels){ std::cout << "Input channel mismatch. Expecting " << input_channels << " channels but image has " << image.channels() << " channels."; return detections; } if(framework == FRAMEWORK_TENSORFLOW){ detections = inferTensorflow(image); }else if(framework == FRAMEWORK_DARKNET){ detections = inferDarknet(image); } return detections; } std::vector DetectorOpenCV::inferTensorflow(cv::Mat image){ std::vector results; auto mean = cv::Scalar(0,0,0); if(image.channels() == 1){ mean = cv::Scalar(0); } // Check for 16-bit double scale_factor = 1/255.0; if(image.elemSize() == 2){ scale_factor = 1/65535.0; } auto input_size = cv::Size(image.cols, image.rows); bool swap_rb = false; // BGR->RGB? bool crop = false; // Use the entire image // No normalising! The model will handle it. auto blob = cv::dnn::blobFromImage(image, 1.0, input_size, mean, swap_rb, crop); //Sets the input to the network net.setInput(blob); // Runs the forward pass to get output of the output layers std::vector outputs; net.forward(outputs, output_names); postProcessTensorflow(image, outputs, results); std::vector layersTimes; double freq = cv::getTickFrequency() / 1000; processing_time = net.getPerfProfile(layersTimes) / freq; std::cout << "Processed in: " << processing_time << std::endl; return results; } void DetectorOpenCV::setNormalisation(double scale_factor, cv::Scalar mean){ this->scale_factor = scale_factor; this->mean = mean; } std::vector DetectorOpenCV::inferDarknet(cv::Mat image){ std::vector results; auto mean = cv::Scalar(0,0,0); if(image.channels() == 1){ mean = cv::Scalar(0); } // Normalisation, check for 16-bit // TODO: have this as a user option if(image.elemSize() == 2){ scale_factor = 1/65535.0; }else{ scale_factor= 1/255.0; } auto input_size = cv::Size(input_width, input_height); bool swap_rb = true; // BGR->RGB? bool crop = false; // Use the entire image auto blob = cv::dnn::blobFromImage(image, scale_factor, input_size, mean, swap_rb, crop); //Sets the input to the network net.setInput(blob); // Runs the forward pass to get output of the output layers std::vector outputs; net.forward(outputs, output_names); // Put efficiency information. The function getPerfProfile returns the // overall time for inference(t) and the timings for each of the layers(in layersTimes) std::vector layersTimes; double freq = cv::getTickFrequency() / 1000; processing_time = net.getPerfProfile(layersTimes) / freq; std::cout << "Processed in: " << processing_time << std::endl; // Remove the bounding boxes with low confidence postProcess(image, outputs, results); return results; } void DetectorOpenCV::annotateImage(cv::Mat &frame, std::vector boxes, cv::Scalar colour, cv::Scalar font_colour){ for(auto &box : boxes){ //Draw a rectangle displaying the bounding box auto top_left = cv::Point(box.rect.left(), box.rect.top()); cv::rectangle(frame, top_left, cv::Point(box.rect.right(), box.rect.bottom()), colour); //Get the label for the class name and its confidence std::string label = cv::format("%.2f", box.confidence); //Display the label at the top of the bounding box int baseLine; cv::Size labelSize = getTextSize(label, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine); cv::putText(frame, label, top_left, cv::FONT_HERSHEY_SIMPLEX, 0.5, font_colour); } } void DetectorOpenCV::runOnProject(LabelProject *project){ QList images; project->getImageList(images); for(auto& image_path : images){ auto image = cv::imread(image_path.toStdString(), cv::IMREAD_UNCHANGED|cv::IMREAD_ANYDEPTH); // Assume we have an alpha image if 4 channels if(image.channels() == 4){ cv::cvtColor(image, image, cv::COLOR_BGRA2BGR); } auto boxes = infer(image); QList existing_boxes; project->getLabels(image_path, existing_boxes); for(auto &box : boxes){ if(!project->classInDB(box.classname)){ project->addClass(box.classname); } // Strip out boxes which are already in the image // assume detector is deterministic bool exists = false; for(auto &existing : existing_boxes){ if(existing.rect == box.rect && existing.classname == box.classname){ exists = true; } } if(!exists){ qDebug() << "Adding label"; project->addLabel(image_path, box); } } } } ================================================ FILE: src/detection/detectoropencv.h ================================================ #ifndef DETECTOROPENCV_H #define DETECTOROPENCV_H #include #include #include #include #include #include #ifdef WITH_CUDA #include #endif #include #include #include #include typedef enum { FRAMEWORK_TENSORFLOW, FRAMEWORK_DARKNET } model_framework; class DetectorOpenCV { public: DetectorOpenCV(); void setImageSize(int width, int height); void loadNetwork(std::string names_file, std::string cfg_file, std::string model_file); void annotateImage(cv::Mat &image, std::vector boxes, cv::Scalar colour = cv::Scalar(0,0,255), cv::Scalar font_colour = cv::Scalar(255,255,255)); std::vector infer(cv::Mat image); std::vector inferDarknet(cv::Mat image); std::vector inferTensorflow(cv::Mat image); void setFramework(model_framework framework){this->framework = framework;} void setFramework(QString framework); void setConfidenceThreshold(double thresh){confThreshold = std::max(0.0, thresh);} void setNMSThreshold(double thresh){nmsThreshold = std::max(0.0, thresh);} void setConvertGrayscale(bool convert){convert_grayscale = convert;} void setConvertDepth(bool convert){convert_depth = convert;} double getConfidenceThreshold(void){ return confThreshold;} double getNMSThreshold(void){ return nmsThreshold;} void setTarget(int target); void setTarget(QString target); void setChannels(int channels); void setNormalisation(double scale_factor, cv::Scalar mean); int getChannels(void){return input_channels;} static model_framework frameworkFromString(QString framework_string); static int targetFromString(QString target_string); void runOnProject(LabelProject *project); private: void postProcess(cv::Mat& frame, const std::vector& outs, std::vector &filtered_outputs); void readNamesFile(std::string class_file = "coco.names"); void getOutputClassNames(void); bool convert_grayscale = true; bool convert_depth = true; double processing_time; double confThreshold = 0.5; // Confidence threshold double nmsThreshold = 0.4; // Non-maximum suppression threshold int input_width = 416; // Width of network's input image int input_height = 416; // Height of network's input image int input_channels = 3; int preferable_target = cv::dnn::DNN_TARGET_OPENCL; model_framework framework = FRAMEWORK_DARKNET; cv::Scalar mean = {0,0,0}; double scale_factor = 1/255.; std::vector class_names; std::vector output_names; cv::dnn::Net net; void postProcessTensorflow(cv::Mat &frame, const std::vector &outputs, std::vector &filtered_boxes); }; #endif // DETECTOROPENCV_H ================================================ FILE: src/detection/detectorsetupdialog.cpp ================================================ #include "detectorsetupdialog.h" #include "ui_detectorsetupdialog.h" DetectorSetupDialog::DetectorSetupDialog(QWidget *parent) : QDialog(parent), ui(new Ui::DetectorSetupDialog) { ui->setupUi(this); connect(ui->cfgPathButton, SIGNAL(clicked()), this, SLOT(setCfgFile())); connect(ui->cfgPathLineEdit, SIGNAL(editingFinished()), this, SLOT(checkForm())); connect(ui->weightPathButton, SIGNAL(clicked(bool)), this, SLOT(setWeightsFile())); connect(ui->weightPathLineEdit, SIGNAL(editingFinished()), this, SLOT(checkForm())); connect(ui->namesPathButton, SIGNAL(clicked(bool)), this, SLOT(setNamesFile())); connect(ui->frameworkComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(setFramework())); connect(ui->targetComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(setTarget())); connect(ui->namesPathLineEdit, SIGNAL(editingFinished()), this, SLOT(checkForm())); connect(ui->convertGrayscaleCheckbox, SIGNAL(clicked(bool)), this, SLOT(setConvertGrayscale())); connect(ui->convertDepthCheckbox, SIGNAL(clicked(bool)), this, SLOT(setConvertDepth())); settings = new QSettings("DeepLabel", "DeepLabel"); cfg_file = settings->value("model_cfg", "").toString(); weight_file = settings->value("model_weights", "").toString(); names_file = settings->value("model_names", "").toString(); convert_grayscale = settings->value("model_convert_grayscale", true).toBool(); ui->convertGrayscaleCheckbox->setChecked(convert_grayscale); convert_depth = settings->value("model_convert_depth", true).toBool(); ui->convertDepthCheckbox->setChecked(convert_depth); image_width = settings->value("model_width", 0).toInt(); image_height = settings->value("model_height", 0).toInt(); image_channels = settings->value("model_channels", 3).toInt(); framework = static_cast(settings->value("model_framework", 0).toInt()); if(framework == FRAMEWORK_DARKNET){ ui->frameworkComboBox->setCurrentText("Darknet (YOLO)"); ui->imageHeightLabel->show(); ui->imageWidthLabel->show(); }else if(framework == FRAMEWORK_TENSORFLOW){ ui->frameworkComboBox->setCurrentText("Tensorflow"); ui->imageHeightLabel->hide(); ui->imageWidthLabel->hide(); } target = settings->value("model_target", cv::dnn::DNN_TARGET_CPU).toInt(); if(target == cv::dnn::DNN_TARGET_CPU){ ui->targetComboBox->setCurrentText("CPU"); }else if(target == cv::dnn::DNN_TARGET_OPENCL){ ui->targetComboBox->setCurrentText("OpenCL"); }else if(target == cv::dnn::DNN_TARGET_OPENCL_FP16){ ui->targetComboBox->setCurrentText("OpenCL FP16"); } #ifdef WITH_CUDA else if(target == cv::dnn::DNN_TARGET_CUDA){ ui->targetComboBox->setCurrentText("CUDA"); }else if(target == cv::dnn::DNN_TARGET_CUDA_FP16){ ui->targetComboBox->setCurrentText("CUDA FP16"); } #endif updateFields(); checkForm(); } void DetectorSetupDialog::updateFields(){ ui->cfgPathLineEdit->setText(cfg_file); ui->weightPathLineEdit->setText(weight_file); ui->namesPathLineEdit->setText(names_file); ui->imageWidthLabel->setText(QString::number(image_width)); ui->imageHeightLabel->setText(QString::number(image_height)); ui->imageChannelsLabel->setText(QString::number(image_channels)); } void DetectorSetupDialog::setConvertGrayscale(void){ convert_grayscale = ui->convertGrayscaleCheckbox->isChecked(); settings->setValue("model_convert_grayscale", convert_grayscale); } bool DetectorSetupDialog::getConvertGrayscale(void){ return convert_grayscale; } void DetectorSetupDialog::setConvertDepth(void){ convert_depth = ui->convertDepthCheckbox->isChecked(); settings->setValue("model_convert_depth", convert_depth); } bool DetectorSetupDialog::getConvertDepth(void){ return convert_depth; } void DetectorSetupDialog::checkForm(void){ ui->buttonBox->button(QDialogButtonBox::Ok)->setDisabled(true); cfg_file = ui->cfgPathLineEdit->text(); weight_file = ui->weightPathLineEdit->text(); names_file = ui->namesPathLineEdit->text(); if(cfg_file == "") return; if(weight_file == "") return; if(names_file == "") return; if(!QFile(cfg_file).exists()){ qDebug() << "Config file doesn't exist"; return; }else if(!getParamsFromConfig()){ return; } if(!QFile(weight_file).exists()){ qDebug() << "Weight file doesn't exist"; return; } if(!QFile(names_file).exists()){ qDebug() << "Names file doesn't exist"; return; } // At this point, all good. ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); settings->setValue("model_width", image_width); settings->setValue("model_height", image_height); settings->setValue("modelchannels", image_channels); settings->setValue("model_cfg", cfg_file); settings->setValue("model_weights", weight_file); settings->setValue("model_names", names_file); } bool DetectorSetupDialog::getParamsFromConfig(void){ qDebug() << "Checking config file"; if(framework == FRAMEWORK_DARKNET){ QSettings darknet_settings(cfg_file, QSettings::IniFormat); darknet_settings.beginGroup("net"); auto keys = darknet_settings.childKeys(); if(!darknet_settings.contains("width")){ qDebug() << "No width parameter"; return false; } if(!darknet_settings.contains("height")){ qDebug() << "No height parameter"; return false; } if(!darknet_settings.contains("channels")){ qDebug() << "No channels parameter"; return false; } auto width = darknet_settings.value("width").toInt(); auto height = darknet_settings.value("height").toInt(); auto channels = darknet_settings.value("channels").toInt(); darknet_settings.endGroup(); qDebug() << width << height << channels; if(width > 0 && height > 0 && channels > 0){ qDebug() << width << height << channels; image_width = width; image_height = height; image_channels = channels; }else{ return false; } }else if(framework == FRAMEWORK_TENSORFLOW){ // In theory we can parse the .pbtxt file to figure out // the input layer parameters, but that either means bringing in // protobuf or loading the entire network via OpenCV. } updateFields(); return true; } QString DetectorSetupDialog::openFile(QString title, QString search_path, QString filter){ QString openDir; if(search_path == ""){ openDir = settings->value("project_folder").toString(); }else{ openDir = QFileInfo(search_path).absoluteDir().absolutePath(); } auto path = QFileDialog::getOpenFileName(this, title, openDir, QString("All files (*.*);;%1").arg(filter), &filter); return path; } void DetectorSetupDialog::setCfgFile(void){ QString filter, title; if(framework == FRAMEWORK_DARKNET){ filter = tr("Config (*.cfg)"); title = tr("Select darknet config file"); }else if(framework == FRAMEWORK_TENSORFLOW){ filter = tr("Config (*.pbtxt)"); title = tr("Select tensorflow config file"); }else{ return; } auto path = openFile(title, cfg_file, filter); if(path != ""){ ui->cfgPathLineEdit->setText(path); } checkForm(); } void DetectorSetupDialog::setWeightsFile(void){ QString filter, title; if(framework == FRAMEWORK_DARKNET){ filter = tr("Weights (*.weights)"); title = tr("Select darknet weights file"); }else if(framework == FRAMEWORK_TENSORFLOW){ filter = tr("Config (*.pb)"); title = tr("Select tensorflow frozen graph"); }else{ return; } auto path = openFile(title, weight_file, filter); if(path != ""){ ui->weightPathLineEdit->setText(path); } checkForm(); } void DetectorSetupDialog::setFramework(void){ qDebug() << "Attempting to set framework to " << ui->frameworkComboBox->currentText(); auto framework = DetectorOpenCV::frameworkFromString(ui->frameworkComboBox->currentText()); settings->setValue("model_framework", framework); } void DetectorSetupDialog::setTarget(void){ qInfo() << "Attempting to set target to " << ui->targetComboBox->currentText(); auto target = DetectorOpenCV::targetFromString(ui->targetComboBox->currentText()); settings->setValue("model_target", target); } int DetectorSetupDialog::getTarget(void){ return target; } void DetectorSetupDialog::setNamesFile(void){ QString filter = tr("Names (*.names)"); QString title = tr("Select darknet names file"); auto path = openFile(title, names_file, filter); if(path != ""){ ui->namesPathLineEdit->setText(path); } checkForm(); } DetectorSetupDialog::~DetectorSetupDialog() { delete ui; } ================================================ FILE: src/detection/detectorsetupdialog.h ================================================ #ifndef DETECTORSETUPDIALOG_H #define DETECTORSETUPDIALOG_H #include #include #include #include #include #include #include #include namespace Ui { class DetectorSetupDialog; } class DetectorSetupDialog : public QDialog { Q_OBJECT public: explicit DetectorSetupDialog(QWidget *parent = nullptr); int getWidth(void){return image_width;} int getHeight(void){return image_height;} int getChannels(void){return image_channels;} QString getNames(void){return names_file;} QString getWeights(void){return weight_file;} QString getCfg(void){return cfg_file;} bool getConvertGrayscale(void); bool getConvertDepth(void); model_framework getFramework(void){return framework;} int getTarget(); ~DetectorSetupDialog(); private slots: void setCfgFile(); void setNamesFile(); void setWeightsFile(); void setFramework(); void setTarget(); void setConvertGrayscale(void); void setConvertDepth(void); void checkForm(); private: Ui::DetectorSetupDialog *ui; bool getParamsFromConfig(); void updateFields(); QSettings* settings; QString cfg_file; QString weight_file; QString names_file; int image_width = 320; int image_height = 240; int image_channels = 3; // default int target = 0; bool convert_grayscale = true; bool convert_depth = true; model_framework framework = FRAMEWORK_TENSORFLOW; QString openFile(QString title, QString search_path="", QString filter=""); }; #endif // DETECTORSETUPDIALOG_H ================================================ FILE: src/detection/detectorsetupdialog.ui ================================================ DetectorSetupDialog 0 0 500 314 500 0 Configure object detector Weight file Darknet (YOLO) Tensorflow CPU CUDA CUDA FP16 OpenCL OpenCL FP16 ... Config file - Channels Convert grayscale images to RGB true Type Image Height - ... Loaded Network Parameters: - ... Names file Image Width Target Convert 16-bit images to 8-bit true Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok cfgPathLineEdit cfgPathButton weightPathLineEdit weightPathButton namesPathLineEdit namesPathButton buttonBox accepted() DetectorSetupDialog accept() 248 254 157 274 buttonBox rejected() DetectorSetupDialog reject() 316 260 286 274 ================================================ FILE: src/exportdialog.cpp ================================================ #include "exportdialog.h" #include "ui_exportdialog.h" ExportDialog::ExportDialog(QWidget *parent) : QDialog(parent), ui(new Ui::ExportDialog) { ui->setupUi(this); toggleExporter(); do_shuffle = ui->randomSplitCheckbox->isChecked(); validation_split_pc = ui->validationSplitSpinbox->value(); connect(ui->exportSelectComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(toggleExporter())); connect(ui->randomSplitCheckbox, SIGNAL(clicked(bool)), this, SLOT(toggleShuffle(bool))); connect(ui->validationSplitSpinbox, SIGNAL(valueChanged(int)), this, SLOT(setValidationSplit(int))); connect(ui->exportLabelledCheckbox, SIGNAL(clicked(bool)), this, SLOT(toggleExportUnlabelled(bool))); connect(ui->trainValCheckbox, SIGNAL(clicked(bool)), this, SLOT(toggleValidationSplit(bool))); connect(ui->gcpBucketLineEdit, SIGNAL(textEdited(QString)), SLOT(setBucketUri(QString))); connect(ui->filePrefixLineEdit, SIGNAL(textEdited(QString)), SLOT(setFilePrefix(QString))); connect(ui->namesFileLineEdit, SIGNAL(textEdited(QString)), SLOT(setNamesFile(QString))); connect(ui->namesFilePushButton, SIGNAL(clicked()), this, SLOT(setNamesFile())); connect(ui->outputFolderLineEdit, SIGNAL(textEdited(QString)), SLOT(setOutputFolder(QString))); connect(ui->outputFolderPushButton, SIGNAL(clicked()), this, SLOT(setOutputFolder())); settings = new QSettings("DeepLabel", "DeepLabel"); ui->validationSplitSpinbox->setValue(settings->value("validation_split_pc", 80).toInt()); toggleShuffle(settings->value("do_shuffle", false).toBool()); toggleExportUnlabelled(settings->value("export_unlabelled", false).toBool()); ui->exportLabelledCheckbox->setChecked(export_unlabelled); toggleValidationSplit(settings->value("validation_split_enable", false).toBool()); ui->trainValCheckbox->setChecked(validation_split_enable); toggleAppendLabels(settings->value("append_labels", false).toBool()); ui->trainValCheckbox->setChecked(append_labels); if(settings->contains("output_folder")){ auto path = settings->value("output_folder").toString(); if(path != ""){ setOutputFolder(path); } } if(settings->contains("names_file")){ auto path = settings->value("names_file").toString(); if(path != ""){ setNamesFile(path); } } if(settings->contains("file_prefix")){ setFilePrefix(settings->value("file_prefix").toString()); } } ExportDialog::~ExportDialog() { delete settings; delete ui; } bool ExportDialog::getExportUnlablled(void){ return export_unlabelled; } bool ExportDialog::getValidationSplitEnabled(void){ return validation_split_enable; } QString ExportDialog::getFilePrefix(void){ return file_prefix; } void ExportDialog::toggleExportUnlabelled(bool res){ export_unlabelled = res; settings->setValue("export_unlabelled", export_unlabelled); } void ExportDialog::setValidationSplit(int value){ if (value < 0 || value > 100) return; validation_split_pc = value; settings->setValue("validation_split_pc", validation_split_pc); } void ExportDialog::toggleValidationSplit(bool enable){ validation_split_enable = enable; settings->setValue("validation_split_enable", enable); } void ExportDialog::toggleAppendLabels(bool enable){ append_labels = enable; settings->setValue("append_labels", enable); } void ExportDialog::toggleShuffle(bool shuffle){ do_shuffle = shuffle; settings->setValue("do_shuffle", do_shuffle); ui->randomSplitCheckbox->setChecked(do_shuffle); } void ExportDialog::setFilePrefix(QString prefix){ if(prefix != ""){ file_prefix = prefix; } settings->setValue("validation_split_pc", validation_split_pc); } void ExportDialog::setOutputFolder(QString path){ if(path == ""){ QString openDir; if(output_folder == ""){ openDir = QDir::homePath(); }else{ openDir = output_folder; } path = QFileDialog::getExistingDirectory(this, tr("Select output folder"), openDir); } if(path != ""){ output_folder = path; ui->outputFolderLineEdit->setText(output_folder); settings->setValue("output_folder", output_folder); } checkOK(); } void ExportDialog::setBucketUri(QString uri){ if(uri != ""){ bucket_uri = uri; } } void ExportDialog::setNamesFile(QString path){ if(path == ""){ QString openDir; if(names_file == ""){ openDir = QDir::homePath(); }else{ openDir = QFileInfo(names_file).absoluteDir().absolutePath(); } path = QFileDialog::getOpenFileName(this, tr("Select darknet names file"), openDir); } if(path != ""){ names_file = path; ui->namesFileLineEdit->setText(names_file); settings->setValue("names_file", names_file); } checkOK(); } bool ExportDialog::checkOK(){ ui->buttonBox->button(QDialogButtonBox::Ok)->setDisabled(true); // If output folder exists if(!QDir(output_folder).exists() || output_folder == ""){ qCritical() << "Export output folder doesn't exist"; return false; } if(ui->exportSelectComboBox->currentText() == "GCP AutoML"){ if(bucket_uri == "") return false; } if(ui->exportSelectComboBox->currentText() == "Darknet"){ // If we're using darknet, check the names // file exists and contains something if(!QFile::exists(names_file)){ qCritical() << "Names file doesn't exist"; return false; } QStringList class_list; QFile fh(names_file); if (fh.open(QIODevice::ReadOnly)) { while (!fh.atEnd()) { // Darknet name file is just a newline delimited list of classes QByteArray line = fh.readLine(); class_list.append(line); } } if(class_list.size() == 0){ qCritical() << "No classes?"; return false; } } ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); return true; } bool ExportDialog::getCreateLabelMap(void){ return ui->labelMapCheckbox->isChecked(); } void ExportDialog::toggleExporter(){ current_exporter = ui->exportSelectComboBox->currentText(); ui->namesFileLineEdit->setEnabled(current_exporter == "Darknet"); ui->namesFilePushButton->setEnabled(current_exporter == "Darknet"); ui->labelMapCheckbox->setEnabled(current_exporter == "Pascal VOC"); ui->gcpBucketLineEdit->setEnabled(current_exporter == "GCP AutoML"); checkOK(); } ================================================ FILE: src/exportdialog.h ================================================ #ifndef EXPORTDIALOG_H #define EXPORTDIALOG_H #include #include #include #include #include #include namespace Ui { class ExportDialog; } class ExportDialog : public QDialog { Q_OBJECT public: explicit ExportDialog(QWidget *parent = nullptr); ~ExportDialog(); QString getExporter(){return current_exporter; } QString getOutputFolder(){return output_folder; } QString getNamesFile(){return names_file; } int getShuffle(){return do_shuffle; } double getValidationSplit(){ return static_cast(validation_split_pc)/100.0; } bool getAppendLabels(){return append_labels;} QString getBucket(){ return bucket_uri; } bool getCreateLabelMap(); bool getExportUnlablled(); bool getValidationSplitEnabled(); QString getFilePrefix(); private slots: void setNamesFile(QString path=""); void setOutputFolder(QString path=""); void setValidationSplit(int value); void toggleShuffle(bool shuffle); void toggleAppendLabels(bool enable); void toggleValidationSplit(bool enable); void toggleExportUnlabelled(bool res); void toggleExporter(); void setBucketUri(QString uri); void setFilePrefix(QString prefix); private: Ui::ExportDialog *ui; bool checkOK(); QSettings *settings; QString output_folder = ""; QString names_file = ""; QString bucket_uri = ""; QString file_prefix = ""; QString current_exporter = "Darknet"; bool do_shuffle = false; bool append_labels = false; bool validation_split_enable = false; int validation_split_pc = 80; bool export_unlabelled; }; #endif // EXPORTDIALOG_H ================================================ FILE: src/exportdialog.ui ================================================ ExportDialog 0 0 338 410 Dialog Names file COCO (JSON) Darknet GCP AutoML Kitti Pascal VOC Validation Split File prefix Output Type: Bucket URI % 100 80 Train/Val Split false 20 0 20 16777215 ... Randomise Split Output Folder false 20 0 20 16777215 ... false gs://your/bucket/path Export unlabelled images true false Save VOC label maps true Append existing label file Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() ExportDialog accept() 248 254 157 274 buttonBox rejected() ExportDialog reject() 316 260 286 274 ================================================ FILE: src/exporter.h ================================================ #ifndef EXPORTER_H #define EXPORTER_H #include #include #include #include #include #include #include #endif // EXPORTER_H ================================================ FILE: src/gcpexporter.cpp ================================================ #include "gcpexporter.h" bool GCPExporter::processImages(const QString folder, const QString filename, const QList images, export_image_type split_type){ QString image_path; QList labels; QString label_filename = QString("%1/%2.txt").arg(folder).arg(filename); QFile f(label_filename); if (!f.open(QIODevice::Append | QIODevice::Truncate)) { return false; } QProgressDialog progress("...", "Abort", 0, images.size(), static_cast(parent())); progress.setWindowModality(Qt::WindowModal); if(!disable_progress){ QString split_text = ""; if(split_type == EXPORT_VAL){ split_text = "VAL"; progress.setWindowTitle("Exporting validation images"); }else if(split_type == EXPORT_TRAIN){ split_text = "TRAIN"; progress.setWindowTitle("Exporting train images"); }else if(split_type == EXPORT_TEST){ split_text = "TEST"; progress.setWindowTitle("Exporting test images"); }else{ split_text = "UNASSIGNED"; } }else{ progress.hide(); } int i=0; foreach(image_path, images){ if(progress.wasCanceled()){ break; } // Check image cv::Mat image = cv::imread(image_path.toStdString()); if(image.empty()) continue; double width = static_cast(image.cols); double height = static_cast(image.rows); project->getLabels(image_path, labels); // Check labels if(!export_unlabelled && labels.size() == 0){ if(!disable_progress){ progress.setValue(i); progress.setLabelText(QString("%1 is unlabelled").arg(image_path)); progress.repaint(); QApplication::processEvents(); } continue; } // Deal with duplicate filenames, etc QString extension = QFileInfo(image_path).suffix(); QString filename_noext = QFileInfo(image_path).completeBaseName(); QString image_filename = QString("%1/%2.%3").arg(folder).arg(filename_noext).arg(extension); // Correct for duplicate file names in output int dupe_file = 1; while(QFile(image_filename).exists()){ image_filename = QString("%1/%2_%3.%4").arg(folder).arg(filename_noext).arg(dupe_file++).arg(extension); } filename_noext = QFileInfo(image_filename).completeBaseName(); auto copied = QFile::copy(image_path, image_filename); if(!copied){ qCritical() << "Failed to copy image" << image_filename; } auto bucket_path = QString("%1/%2.%3").arg(bucket_uri).arg(filename_noext).arg(extension); for(auto &label : labels){ auto gcp_label = QString("%1,%2,%3,%4,%5,,,%6,%7,,\n") .arg(split_type) .arg(bucket_path) .arg(label.classname) .arg(QString::number(static_cast(label.rect.topLeft().x())/width)) .arg(QString::number(static_cast(label.rect.topLeft().y())/height)) .arg(QString::number(static_cast(label.rect.bottomRight().x())/width)) .arg(QString::number(static_cast(label.rect.bottomRight().x())/height)); qDebug() << gcp_label; f.write(gcp_label.toUtf8()); } if(!disable_progress){ progress.setValue(i++); progress.setLabelText(image_filename); QApplication::processEvents(); } } return true; } bool GCPExporter::setOutputFolder(const QString folder){ if(folder == "") return false; output_folder = folder; //Make output folder if it doesn't exist if (!QDir(output_folder).exists()){ qInfo() << "Making output folder" << output_folder; QDir().mkpath(output_folder); } image_folder = QDir::cleanPath(output_folder+"/images"); if (!QDir(image_folder).exists()){ qInfo() << "Making validation folder" << image_folder; QDir().mkpath(image_folder); } image_folder = QDir::cleanPath(image_folder); return true; } void GCPExporter::setBucket(QString uri, bool local){ if(!uri.startsWith("gs://") && !local){ bucket_uri = QString("gs://%1").arg(uri); }else{ bucket_uri = uri; } } void GCPExporter::process(){ processImages(image_folder, "labels", train_set, EXPORT_TRAIN); processImages(image_folder, "labels", validation_set, EXPORT_VAL); } ================================================ FILE: src/gcpexporter.h ================================================ #ifndef GCPEXPORTER_H #define GCPEXPORTER_H #include class GCPExporter : public BaseExporter { Q_OBJECT public: explicit GCPExporter(LabelProject *project, QObject *parent = nullptr) : BaseExporter(project, parent){} public slots: void process(); void setBucket(QString uri, bool local=false); bool setOutputFolder(const QString folder); private: bool processImages(const QString output_folder, QString filename, const QList images, export_image_type split_type=EXPORT_TRAIN); QString bucket_uri; QString image_folder; }; #endif // GCPEXPORTER_H ================================================ FILE: src/imagedisplay.cpp ================================================ #include "imagedisplay.h" #include "ui_imagedisplay.h" std::unordered_map ImageDisplay::colour_hashmap{ { "Cividis", cv::COLORMAP_CIVIDIS }, { "Inferno", cv::COLORMAP_INFERNO }, { "Magma", cv::COLORMAP_MAGMA }, { "Hot", cv::COLORMAP_HOT }, { "Bone", cv::COLORMAP_BONE }, { "Plasma", cv::COLORMAP_PLASMA }, { "Jet", cv::COLORMAP_JET }, { "Rainbow", cv::COLORMAP_RAINBOW }, { "Ocean", cv::COLORMAP_OCEAN }, { "Viridis", cv::COLORMAP_VIRIDIS } }; ImageDisplay::ImageDisplay(QWidget *parent) : QWidget(parent), ui(new Ui::ImageDisplay) { ui->setupUi(this); imageLabel = new ImageLabel; scrollArea = new QScrollArea(this); ui->mainLayout->addWidget(scrollArea); scrollArea->setWidget(imageLabel); scrollArea->setAlignment(Qt::AlignCenter); scrollArea->setBackgroundRole(QPalette::Shadow); connect(ui->fitToWindowButton, SIGNAL(clicked()), this, SLOT(updateDisplay())); connect(ui->resetZoomButton, SIGNAL(clicked()), this, SLOT(resetZoom())); connect(ui->zoomInButton, SIGNAL(clicked()), this, SLOT(zoomIn())); connect(ui->zoomOutButton, SIGNAL(clicked()), this, SLOT(zoomOut())); connect(ui->zoomSpinBox, SIGNAL(valueChanged(int)), this, SLOT(scaleImage())); QtAwesome* awesome = new QtAwesome( qApp ); awesome->initFontAwesome(); ui->zoomInButton->setIcon(awesome->icon(fa::searchplus)); ui->zoomOutButton->setIcon(awesome->icon(fa::searchminus)); ui->resetZoomButton->setIcon(awesome->icon(fa::home)); updateDisplay(); } ImageDisplay::~ImageDisplay() { delete ui; } void ImageDisplay::setImagePath(QString path){ if(path != ""){ current_imagepath = path; loadPixmap(); } } void ImageDisplay::clearPixmap(void){ pixmap = QPixmap(); imageLabel->setPixmap(pixmap); } void ImageDisplay::convert16(cv::Mat &source, double minval, double maxval){ if(minval < 0 || maxval < 0){ cv::minMaxIdx(source, &minval, &maxval); } double range = maxval-minval; double scale_factor = 255.0/range; source.convertTo(source, CV_32FC1); source -= minval; source *= scale_factor; source.convertTo(source, CV_8UC1); return; } cv::Mat ImageDisplay::getOriginalImage(void){ return original_image; } void ImageDisplay::loadPixmap(){ if(current_imagepath == "") return; original_image = cv::imread(current_imagepath.toStdString(), cv::IMREAD_UNCHANGED|cv::IMREAD_ANYDEPTH); if(original_image.empty()){ qCritical() << "Failed to load image " << current_imagepath; return; } display_image = original_image.clone(); // Default to single channel 8-bit image format = QImage::Format_Grayscale8; bit_depth = 8; if(original_image.elemSize() == 2){ convert16(display_image); bit_depth = 16; } if(display_image.channels() == 3){ cv::cvtColor(display_image, display_image, cv::COLOR_BGR2RGB); format = QImage::Format_RGB888; bit_depth = 24; }else if (display_image.channels() == 4){ cv::cvtColor(display_image, display_image, cv::COLOR_BGRA2RGBA); format = QImage::Format_RGBA8888; bit_depth = 32; }else if(display_image.channels() == 1 && apply_colourmap){ cv::applyColorMap(display_image, display_image, colour_map); cv::cvtColor(display_image, display_image, cv::COLOR_BGR2RGB); format = QImage::Format_RGB888; } pixmap = QPixmap::fromImage(QImage(display_image.data, display_image.cols, display_image.rows, static_cast(display_image.step), format)); imageLabel->setImage(display_image); updateDisplay(); emit image_loaded(); } void ImageDisplay::setColourMap(QString map){ auto map_str = map.toStdString(); if(colour_hashmap.count(map_str)){ colour_map = colour_hashmap[map_str]; loadPixmap(); } } void ImageDisplay::toggleColourMap(bool enable){ apply_colourmap = enable; loadPixmap(); } void ImageDisplay::adjustScrollBar(QScrollBar *scrollBar, double factor) { scrollBar->setValue(int(factor * scrollBar->value() + ((factor - 1) * scrollBar->pageStep()/2))); } void ImageDisplay::scaleImage(void) { if(pixmap.isNull()) return; image_scale_factor = static_cast(ui->zoomSpinBox->value()) / 100.0; imageLabel->zoom(image_scale_factor); adjustScrollBar(scrollArea->horizontalScrollBar(), image_scale_factor); adjustScrollBar(scrollArea->verticalScrollBar(), image_scale_factor); ui->zoomInButton->setEnabled(image_scale_factor <= 3.0); ui->zoomOutButton->setEnabled(image_scale_factor >= 0.33); } void ImageDisplay::zoomIn() { if(fit_to_window) return; ui->zoomSpinBox->setValue(ui->zoomSpinBox->value()*1.2); } void ImageDisplay::zoomOut() { if(fit_to_window) return; ui->zoomSpinBox->setValue(ui->zoomSpinBox->value()*0.8); } void ImageDisplay::resetZoom(){ ui->zoomSpinBox->setValue(100); } void ImageDisplay::updateDisplay() { if(pixmap.isNull()) return; fit_to_window = ui->fitToWindowButton->isChecked(); // Decide whether to use scrollbars scrollArea->setWidgetResizable(fit_to_window); // Auto-scale the image to the size of the scrollarea, // or leave it full-size imageLabel->setScaledContents(fit_to_window); imageLabel->setPixmap(pixmap); repaint(); } ================================================ FILE: src/imagedisplay.h ================================================ #ifndef IMAGEDISPLAY_H #define IMAGEDISPLAY_H #include #include #include #include #include #include #include #include #include namespace Ui { class ImageDisplay; } class ImageDisplay : public QWidget { Q_OBJECT public: explicit ImageDisplay(QWidget *parent = nullptr); ~ImageDisplay(); public slots: void setImagePath(QString path); ImageLabel* getImageLabel(void){return imageLabel;} int getBitDepth(void){return bit_depth;} void setColourMap(QString map); void toggleColourMap(bool enable); cv::Mat getOriginalImage(); void clearPixmap(); private: cv::Mat display_image; cv::Mat original_image; QPixmap pixmap; Ui::ImageDisplay *ui; QString current_imagepath; void convert16(cv::Mat &source, double minval=-1, double maxval=-1); ImageLabel* imageLabel; QScrollArea* scrollArea; bool fit_to_window = false; double image_scale_factor = 1.0; bool apply_colourmap = true; int colour_map = cv::COLORMAP_MAGMA; QImage::Format format = QImage::Format_Grayscale8; int bit_depth = 8; static std::unordered_map colour_hashmap; private slots: void loadPixmap(); void updateDisplay(); void resetZoom(); void scaleImage(); void adjustScrollBar(QScrollBar *scrollBar, double factor); void zoomIn(); void zoomOut(); signals: void image_loaded(); }; #endif // IMAGEDISPLAY_H ================================================ FILE: src/imagedisplay.ui ================================================ ImageDisplay 0 0 400 300 Form Fit to window true 0 0 0 1 16777215 16777215 true 0 0 16777215 16777215 true 0 0 16777215 16777215 true % 33 300 100 ================================================ FILE: src/imagelabel.cpp ================================================ #include "imagelabel.h" ImageLabel::ImageLabel(QWidget *parent) : QLabel(parent) { setMinimumSize(1,1); setAlignment(Qt::AlignCenter); setMouseTracking(true); // This is important to preserve the aspect ratio setScaledContents(true); // Dark background setBackgroundRole(QPalette::Shadow); // Size policy setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); setFocusPolicy(Qt::StrongFocus); rubberBand = new QRubberBand(QRubberBand::Rectangle, this); setDrawMode(); } void ImageLabel::setPixmap ( QPixmap & p) { base_pixmap = p; drawLabels(); QPixmap pixmap; resize(pixmap.size()); } int ImageLabel::heightForWidth( int width ) const { return base_pixmap.isNull() ? height() : static_cast((static_cast(base_pixmap.height())*width)/base_pixmap.width()); } QSize ImageLabel::sizeHint() const { int w = width(); return QSize( w, heightForWidth(w) ); } void ImageLabel::resizeEvent(QResizeEvent * e) { if(!base_pixmap.isNull()){ drawLabels(); }else{ e->ignore(); } } void ImageLabel::zoom(double factor){ zoom_factor = factor; scaledPixmap(); if(zoom_factor == 1.0){ resize(base_pixmap.size()); }else{ resize(scaled_pixmap.size()); } } QPixmap ImageLabel::scaledPixmap(void) { if(base_pixmap.isNull()) return QPixmap(); if(shouldScaleContents){ scaled_pixmap = base_pixmap.scaled( size(), Qt::KeepAspectRatio, Qt::SmoothTransformation); }else if(zoom_factor != 1.0){ scaled_pixmap = base_pixmap.scaled( zoom_factor*base_pixmap.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation); }else{ scaled_pixmap = base_pixmap; } scaled_width = scaled_pixmap.width(); scaled_height = scaled_pixmap.height(); scale_factor = static_cast(scaled_height)/base_pixmap.height(); return scaled_pixmap; } void ImageLabel::setDrawMode() { current_mode = MODE_DRAW; setCursor(Qt::CrossCursor); rubberBand->setGeometry(QRect(bbox_origin, QSize())); rubberBand->show(); setBoundingBoxes(bboxes); } void ImageLabel::setDrawDragMode() { current_mode = MODE_DRAW_DRAG; rubberBand->setGeometry(QRect(bbox_origin, QSize())); rubberBand->show(); setBoundingBoxes(bboxes); } void ImageLabel::setSelectMode(){ current_mode = MODE_SELECT; setCursor(Qt::PointingHandCursor); rubberBand->hide(); setBoundingBoxes(bboxes); } QPoint ImageLabel::getScaledImageLocation(QPoint location){ // If the image is fit to window QPoint scaled_location = location; if(scale_factor != 1.0){ // Get the location on the image, accounting for padding scaled_location.setX(scaled_location.x() - (width() - scaled_width)/2); scaled_location.setY(scaled_location.y() - (height() - scaled_height)/2); scaled_location.setX(static_cast(scaled_location.x() / scale_factor)); scaled_location.setY(static_cast(scaled_location.y() / scale_factor)); } return scaled_location; } void ImageLabel::mousePressEvent(QMouseEvent *ev){ if(base_pixmap.isNull()) return; QPoint click_location = ev->pos(); if (current_mode == MODE_SELECT && ev->button() == Qt::LeftButton) { bool clicked = true; bool state_change = false; auto active_box = checkBoundingBoxes(click_location, state_change, clicked); if (state_change) { drawLabels(); } if (active_box.label_id > 0) { edit_state = EDITING_BOX; editing_bbox = active_box; selected_bbox = active_box; initial_edit_centre = click_location; } else { selected_bbox = BoundingBox(); edit_state = EDIT_WAIT; } } else if (current_mode == MODE_DRAW && ev->button() == Qt::LeftButton) { if (bbox_state == WAIT_START) { bbox_origin = click_location; rubberBand->setGeometry(QRect(bbox_origin, QSize())); rubberBand->show(); bbox_state = DRAWING_BBOX; } else if (bbox_state == DRAWING_BBOX) { bbox_final = click_location; QRect bbox(bbox_origin, bbox_final); bbox = clip(bbox.normalized()); bbox_origin = bbox.topLeft(); bbox_final = bbox.bottomRight(); rubberBand->setGeometry(bbox); bbox_state = WAIT_START; } } } void ImageLabel::mouseReleaseEvent(QMouseEvent *ev) { if (current_mode == MODE_SELECT && edit_state == EDITING_BOX) { auto temp = editing_bbox; editing_bbox = BoundingBox(); updateLabel(selected_bbox, temp); edit_state = EDIT_WAIT; setBoundingBoxes(bboxes); } else { ev->ignore(); } } void ImageLabel::mouseMoveEvent(QMouseEvent *ev) { if (base_pixmap.isNull()) return; if (bbox_state == DRAWING_BBOX && current_mode == MODE_DRAW) { QRect bbox = QRect(bbox_origin, ev->pos()).normalized(); rubberBand->setGeometry(bbox); } if (current_mode == MODE_SELECT) { if (edit_state == EDIT_WAIT) { bool state_change; checkBoundingBoxes(ev->pos(), state_change); if (state_change) { drawLabels(); } } else if (edit_state == EDITING_BOX) { editBoxCoords(editing_bbox, ev->pos()); drawLabels(); } } } void ImageLabel::editBoxCoords(BoundingBox &bbox, QPoint location) { auto scaled_location = getScaledImageLocation(location); // Edge cases if (bbox.selected_edge == EDGE_TOP) { bbox.rect.setTop(scaled_location.y()); } else if (bbox.selected_edge == EDGE_BOTTOM) { bbox.rect.setBottom(scaled_location.y()); } else if (bbox.selected_edge == EDGE_LEFT) { bbox.rect.setLeft(scaled_location.x()); } else if (bbox.selected_edge == EDGE_RIGHT) { bbox.rect.setRight(scaled_location.x()); } // Corner cases if (bbox.selected_corner == CORNER_BOTTOMLEFT) { bbox.rect.setBottomLeft(scaled_location); } else if (bbox.selected_corner == CORNER_BOTTOMRIGHT) { bbox.rect.setBottomRight(scaled_location); } else if (bbox.selected_corner == CORNER_TOPLEFT) { bbox.rect.setTopLeft(scaled_location); } else if (bbox.selected_corner == CORNER_TOPRIGHT) { bbox.rect.setTopRight(scaled_location); } if (bbox.is_selected) { int width = bbox.rect.width(); int height = bbox.rect.height(); auto delta = scaled_location - getScaledImageLocation(initial_edit_centre); bbox.rect.setTopLeft( {bbox.rect.topLeft().x() + delta.x(), bbox.rect.topLeft().y() + delta.y()}); bbox.rect.setWidth(width); bbox.rect.setHeight(height); initial_edit_centre = location; } bbox.rect = bbox.rect.normalized(); } bool ImageLabel::isSelected(BoundingBox bbox, QPoint location, int padding) { auto rect = QRect(QPoint(bbox.rect.topLeft().x() + padding, bbox.rect.topLeft().y() + padding), QPoint(bbox.rect.bottomRight().x() - padding, bbox.rect.bottomRight().y() - padding)); return rect.contains(location); } BoundingBox ImageLabel::checkBoundingBoxes(QPoint location, bool &state_change, bool click) { state_change = false; bool something_selected = false; BoundingBox active; for (auto &bbox : bboxes) { // Check for selected (centre hitbox) if (click) { auto prev_select = bbox.is_selected; bool selected = isSelected(bbox, getScaledImageLocation(location)); if (selected && !something_selected) { bbox.is_selected = true; selected_bbox = bbox; active = bbox; something_selected = true; emit setCurrentClass(selected_bbox.classname); } else { bbox.is_selected = false; } state_change |= (prev_select == bbox.is_selected); } // Check for selected edge (edge hitboxes) auto prev_edge = bbox.selected_edge; bbox.selected_edge = getSelectedEdge(bbox, getScaledImageLocation(location)); if (bbox.selected_edge != EDGE_NONE) { active = bbox; } state_change |= (prev_edge == bbox.selected_edge); // Check for selected corner (corner hitboxes) auto prev_corner = bbox.selected_corner; bbox.selected_corner = getSelectedCorner(bbox, getScaledImageLocation(location)); if (bbox.selected_corner != CORNER_NONE) { active = bbox; } state_change |= (prev_corner == bbox.selected_corner); } return active; } QRect ImageLabel::clip(QRect bbox){ auto xpad = (width() - scaled_width)/2; bbox.setLeft(std::max(xpad, bbox.left())); bbox.setRight(std::min(width()-xpad, bbox.right())); auto ypad = (height() - scaled_height)/2; bbox.setTop(std::max(ypad, bbox.top())); bbox.setBottom(std::min(height()-ypad, bbox.bottom())); return bbox; } void ImageLabel::drawBoundingBox(BoundingBox bbox) { auto colour_list = QColor::colorNames(); QColor colour = QColor(colour_list.at(std::max(0, bbox.classid) % colour_list.size())); drawBoundingBox(bbox, colour); } QRect ImageLabel::getPaddedRectangle(QPoint location, int pad) { return QRect(location.x() - pad, location.y() - pad, 2 * pad, 2 * pad); } void ImageLabel::drawBoundingBox(BoundingBox bbox, QColor colour) { if (scaled_pixmap.isNull()) return; QPainter painter; painter.begin(&scaled_pixmap); QPen pen(colour, 2); painter.setPen(pen); auto scaled_bbox = bbox.rect; scaled_bbox.setRight(static_cast(scaled_bbox.right() * scale_factor)); scaled_bbox.setLeft(static_cast(scaled_bbox.left() * scale_factor)); scaled_bbox.setTop(static_cast(scaled_bbox.top() * scale_factor)); scaled_bbox.setBottom(static_cast(scaled_bbox.bottom() * scale_factor)); if(bbox.classname != ""){ //painter.fillRect(QRect(scaled_bbox.bottomLeft(), scaled_bbox.bottomRight()+QPoint(0,-10)).normalized(), QBrush(Qt::white)); painter.setFont(QFont("Helvetica", 10)); painter.drawText(scaled_bbox.bottomLeft(), bbox.classname); } painter.drawRect(scaled_bbox); if (current_mode == MODE_SELECT) { QPen pen(Qt::white, 4); painter.setPen(pen); painter.drawRect(getPaddedRectangle(scaled_bbox.topLeft(), 5)); painter.drawRect(getPaddedRectangle(scaled_bbox.topRight(), 5)); painter.drawRect(getPaddedRectangle(scaled_bbox.bottomLeft(), 5)); painter.drawRect(getPaddedRectangle(scaled_bbox.bottomRight(), 5)); if (bbox.selected_edge != EDGE_NONE) { QPen pen(Qt::red, 4); painter.setPen(pen); if (bbox.selected_edge == EDGE_LEFT) { painter.drawLine(scaled_bbox.topLeft(), scaled_bbox.bottomLeft()); } else if (bbox.selected_edge == EDGE_RIGHT) { painter.drawLine(scaled_bbox.topRight(), scaled_bbox.bottomRight()); } else if (bbox.selected_edge == EDGE_BOTTOM) { painter.drawLine(scaled_bbox.bottomRight(), scaled_bbox.bottomLeft()); } else { painter.drawLine(scaled_bbox.topLeft(), scaled_bbox.topRight()); } } if (bbox.selected_corner != CORNER_NONE) { QPen pen(Qt::red, 4); painter.setPen(pen); if (bbox.selected_corner == CORNER_TOPLEFT) { painter.drawRect(getPaddedRectangle(scaled_bbox.topLeft(), 5)); } else if (bbox.selected_corner == CORNER_TOPRIGHT) { painter.drawRect(getPaddedRectangle(scaled_bbox.topRight(), 5)); } else if (bbox.selected_corner == CORNER_BOTTOMLEFT) { painter.drawRect(getPaddedRectangle(scaled_bbox.bottomLeft(), 5)); } else { painter.drawRect(getPaddedRectangle(scaled_bbox.bottomRight(), 5)); } } } painter.end(); } void ImageLabel::setBoundingBoxes(QList input_bboxes){ bboxes.clear(); bboxes = input_bboxes; drawLabels(); } void ImageLabel::setClassname(QString classname) { current_classname = classname; if(selected_bbox.classname != classname){ auto new_bbox = selected_bbox; new_bbox.classname = classname; emit updateLabel(selected_bbox, new_bbox); } } void ImageLabel::setScaledContents(bool should_scale){ shouldScaleContents = should_scale; if(!shouldScaleContents){ scale_factor = 1.0; } } bool ImageLabel::scaleContents(void){ return shouldScaleContents; } SelectedEdge ImageLabel::getSelectedEdge(BoundingBox bbox, QPoint location) { auto edge = EDGE_NONE; auto rect = bbox.rect; auto left_hitbox = QRect(QPoint(rect.topLeft().x() - point_threshold, rect.topLeft().y() + point_threshold), QPoint(rect.bottomLeft().x() + point_threshold, rect.bottomLeft().y() - point_threshold)); auto top_hitbox = QRect(QPoint(rect.topLeft().x() + point_threshold, rect.topLeft().y() - point_threshold), QPoint(rect.topRight().x() - point_threshold, rect.topRight().y() + point_threshold)); auto right_hitbox = QRect(QPoint(rect.topRight().x() - point_threshold, rect.topRight().y() + point_threshold), QPoint(rect.bottomRight().x() + point_threshold, rect.bottomRight().y() - point_threshold)); auto bottom_hitbox = QRect(QPoint(rect.bottomLeft().x() + point_threshold, rect.bottomLeft().y() - point_threshold), QPoint(rect.bottomRight().x() - point_threshold, rect.bottomRight().y() + point_threshold)); bool proper = true; if (left_hitbox.contains(location, proper)) { edge = EDGE_LEFT; } else if (right_hitbox.contains(location, proper)) { edge = EDGE_RIGHT; } else if (top_hitbox.contains(location, proper)) { edge = EDGE_TOP; } else if (bottom_hitbox.contains(location, proper)) { edge = EDGE_BOTTOM; } return edge; } double ImageLabel::pointDistance(QPoint p1, QPoint p2) { auto l = QLine(p1, p2); return std::sqrt(std::pow(l.dx(), 2) + std::pow(l.dy(), 2)); } SelectedCorner ImageLabel::getSelectedCorner(BoundingBox bbox, QPoint location) { auto corner = CORNER_NONE; auto rect = bbox.rect; auto top_left_dist = pointDistance(rect.topLeft(), location); auto top_right_dist = pointDistance(rect.topRight(), location); auto bottom_left_dist = pointDistance(rect.bottomLeft(), location); auto bottom_right_dist = pointDistance(rect.bottomRight(), location); if (top_left_dist < point_threshold) { corner = CORNER_TOPLEFT; } else if (top_right_dist < point_threshold) { corner = CORNER_TOPRIGHT; } else if (bottom_left_dist < point_threshold) { corner = CORNER_BOTTOMLEFT; } else if (bottom_right_dist < point_threshold) { corner = CORNER_BOTTOMRIGHT; } return corner; } void ImageLabel::drawLabels(QPoint cursor_location) { scaledPixmap(); if (scale_factor == 1.0) { scaled_pixmap = base_pixmap; } BoundingBox bbox; auto colour_list = QColor::colorNames(); foreach (bbox, bboxes) { if (bbox.label_id == editing_bbox.label_id) { drawBoundingBox(editing_bbox, Qt::red); } else { if (bbox.label_id == selected_bbox.label_id) { drawBoundingBox(bbox, Qt::green); } else { drawBoundingBox(bbox); } } } QLabel::setPixmap(scaled_pixmap); } void ImageLabel::addLabel(QRect rect, QString classname){ BoundingBox new_bbox; new_bbox.classname = classname; new_bbox.rect = rect; bboxes.append(new_bbox); emit newLabel(new_bbox); drawLabels(); } void ImageLabel::keyPressEvent(QKeyEvent *event) { if(event->key() == Qt::Key_Backspace || event->key() == Qt::Key_Delete){ emit removeLabel(selected_bbox); } else if (event->key() == Qt::Key_Escape) { rubberBand->setGeometry(QRect(bbox_origin, QSize())); bbox_state = WAIT_START; selected_bbox = BoundingBox(); bool state; checkBoundingBoxes({-1, -1}, state, true); drawLabels(); } else if (event->key() == Qt::Key_Space && bbox_state == WAIT_START) { if(rubberBand->width() > 0 && rubberBand->height() > 0){ if(current_classname == ""){ qWarning() << "No class selected!"; }else{ QRect bbox_rect; bbox_rect = QRect(bbox_origin, bbox_final); bbox_rect.setTopLeft(getScaledImageLocation(bbox_rect.topLeft())); bbox_rect.setBottomRight(getScaledImageLocation(bbox_rect.bottomRight())); addLabel(bbox_rect, current_classname); rubberBand->setGeometry(QRect(bbox_origin, QSize())); } }else if(event->key() == 'o'){ emit setOccluded(selected_bbox); drawLabels(); } } else { event->ignore(); } } ================================================ FILE: src/imagelabel.h ================================================ #ifndef IMAGELABEL_H #define IMAGELABEL_H #include #include #include #include #include #include #include #include enum drawState { WAIT_START, DRAWING_BBOX, }; enum interactionState { MODE_DRAW, MODE_DRAW_DRAG, MODE_EDIT, MODE_MOVE, MODE_SELECT, }; enum editState { EDIT_WAIT, EDIT_START, EDITING_BOX, MOVING_BOX }; class ImageLabel : public QLabel { Q_OBJECT public: explicit ImageLabel(QWidget *parent = nullptr); virtual int heightForWidth( int width ) const; virtual QSize sizeHint() const; void setScaledContents(bool scale_factor); QList getBoundingBoxes(){return bboxes;} cv::Mat getImage(void){return image;} bool scaleContents(void); signals: void newLabel(BoundingBox); void removeLabel(BoundingBox); void updateLabel(BoundingBox, BoundingBox); void setOccluded(BoundingBox); void setCurrentClass(QString); public slots: void setPixmap ( QPixmap & ); void setImage(cv::Mat &image){this->image = image;} void setBoundingBoxes(QList input_bboxes); void setClassname(QString classname); void addLabel(QRect rect, QString classname); void zoom(double factor); void setDrawMode(); void setDrawDragMode(); void setSelectMode(); void resizeEvent(QResizeEvent *); void mousePressEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void keyPressEvent(QKeyEvent *event); private: cv::Mat image; QPixmap pix; QPixmap base_pixmap; QPixmap scaled_pixmap; QString current_classname; bool shouldScaleContents = false; QList bboxes; BoundingBox selected_bbox; BoundingBox editing_bbox; void drawBoundingBox(BoundingBox bbox); void drawBoundingBox(BoundingBox bbox, QColor colour); void drawLabels(QPoint cursor_location = QPoint(-1, -1)); QPoint getScaledImageLocation(QPoint location); QPixmap scaledPixmap(void); QRect clip(QRect bbox); QPainter* painter; drawState bbox_state = WAIT_START; editState edit_state = EDIT_WAIT; interactionState current_mode = MODE_DRAW; QPoint bbox_origin, bbox_final; QRubberBand* rubberBand; int bbox_width = 0; int bbox_height = 0; double scale_factor = 1.0; double zoom_factor = 1.0; int scaled_width; int scaled_height; int point_threshold = 5; void drawBoundingBoxes(QPoint location); SelectedEdge getSelectedEdge(BoundingBox bbox, QPoint location); SelectedCorner getSelectedCorner(BoundingBox bbox, QPoint location); bool isSelected(BoundingBox bbox, QPoint location, int padding = 5); BoundingBox checkBoundingBoxes(QPoint location, bool &state_change, bool click = false); QRect getPaddedRectangle(QPoint location, int pad); double pointDistance(QPoint p1, QPoint p2); void editBoxCoords(BoundingBox &bbox, QPoint location); QPoint initial_edit_centre; }; #endif // IMAGELABEL_H ================================================ FILE: src/importdialog.cpp ================================================ #include "importdialog.h" #include "ui_importdialog.h" ImportDialog::ImportDialog(QWidget *parent) : QDialog(parent), ui(new Ui::ImportDialog) { ui->setupUi(this); connect(ui->importSelectComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(toggleImporter())); connect(ui->importLabelledCheckbox, SIGNAL(clicked(bool)), this, SLOT(setImportUnlabelled(bool))); connect(ui->relativeImageCheckbox, SIGNAL(clicked(bool)), this, SLOT(setRelativePaths(bool))); connect(ui->namesFileLineEdit, SIGNAL(textEdited(QString)), SLOT(setNamesFile(QString))); connect(ui->namesFilePushButton, SIGNAL(clicked()), this, SLOT(setNamesFile())); connect(ui->inputListLineEdit, SIGNAL(textEdited(QString)), SLOT(setInputFile(QString))); connect(ui->inputListPushButton, SIGNAL(clicked()), this, SLOT(setInputFile())); connect(ui->relativeImageRootLineEdit, SIGNAL(textEdited(QString)), SLOT(setRelativeImagePath(QString))); connect(ui->relativeImageRootPushButton, SIGNAL(clicked()), this, SLOT(setRelativeImagePath())); connect(ui->annotationLineEdit, SIGNAL(textEdited(QString)), SLOT(setAnnotationFile(QString))); connect(ui->annotationPushButton, SIGNAL(clicked()), this, SLOT(setAnnotationFile())); settings = new QSettings("DeepLabel", "DeepLabel"); setImportUnlabelled(settings->value("import_unlabelled", false).toBool()); ui->importLabelledCheckbox->setChecked(import_unlabelled); setRelativePaths(settings->value("relative_image_paths", false).toBool()); ui->relativeImageCheckbox->setChecked(relative_image_paths); if(settings->contains("import_format")){ auto format = settings->value("import_format").toString(); if(format != ""){ setImporter(format); } }else{ setImporter("Darknet"); } if(settings->contains("input_file")){ auto path = settings->value("input_file").toString(); if(path != ""){ setInputFile(path); } } if(settings->contains("names_file")){ auto path = settings->value("names_file").toString(); if(path != ""){ setNamesFile(path); } } if(settings->contains("annotation_file")){ auto path = settings->value("annotation_file").toString(); if(path != ""){ setAnnotationFile(path); } } if (settings->contains("relative_root")) { auto path = settings->value("relative_root").toString(); if (path != "") { setRelativeImagePath(path); } } } ImportDialog::~ImportDialog() { delete ui; } bool ImportDialog::getImportUnlabelled(void){ return import_unlabelled; } void ImportDialog::setImportUnlabelled(bool res){ import_unlabelled = res; settings->setValue("import_unlabelled", import_unlabelled); } void ImportDialog::setRelativePaths(bool res) { relative_image_paths = res; settings->setValue("relative_image_paths", relative_image_paths); } void ImportDialog::setRelativeImagePath(QString path) { if (path == "") { QString openDir; if (relative_root == "") { openDir = QDir::homePath(); } else { openDir = QDir(relative_root).path(); } path = QFileDialog::getExistingDirectory(this, tr("Select relative root folder"), openDir); } if (path != "") { relative_root = path; ui->relativeImageRootLineEdit->setText(relative_root); settings->setValue("relative_root", relative_root); } checkOK(); } void ImportDialog::setInputFile(QString path){ if(path == ""){ QString openDir; if(input_file == ""){ openDir = QDir::homePath(); }else{ openDir = QDir(input_file).path(); } if(current_importer == "MOT" || current_importer == "BirdsAI"){ path = QFileDialog::getExistingDirectory(this, tr("Select sequence folder"), openDir); }else if(current_importer == "Coco" || current_importer == "PascalVOC"){ path = QFileDialog::getExistingDirectory(this, tr("Select image folder"), openDir); }else{ path = QFileDialog::getOpenFileName(this, tr("Select input file"), openDir); } } if(path != ""){ input_file = path; ui->inputListLineEdit->setText(input_file); settings->setValue("input_file", input_file); } checkOK(); } void ImportDialog::setNamesFile(QString path){ if(path == ""){ QString openDir; if(names_file == ""){ openDir = QDir::homePath(); }else{ openDir = QFileInfo(names_file).absoluteDir().absolutePath(); } path = QFileDialog::getOpenFileName(this, tr("Select darknet names file"), openDir); } if(path != ""){ names_file = path; ui->namesFileLineEdit->setText(names_file); settings->setValue("names_file", names_file); } checkOK(); } void ImportDialog::setAnnotationFile(QString path){ if(path == ""){ QString openDir; if(annotation_file == ""){ openDir = QDir::homePath(); }else{ openDir = QFileInfo(annotation_file).absoluteDir().absolutePath(); } if(current_importer == "BirdsAI" || current_importer == "PascalVOC"){ path = QFileDialog::getExistingDirectory(this, tr("Select annotation folder"), openDir); }else{ path = QFileDialog::getOpenFileName(this, tr("Select annotation file"), openDir); } } if(path != ""){ annotation_file = path; ui->annotationLineEdit->setText(annotation_file); settings->setValue("annotation_file", annotation_file); } checkOK(); } bool ImportDialog::checkOK(){ ui->namesFileLineEdit->setEnabled(current_importer != "Coco"); ui->buttonBox->button(QDialogButtonBox::Ok)->setDisabled(true); if(current_importer == "Coco"){ ui->namesFileLineEdit->setDisabled(true); ui->namesFilePushButton->setDisabled(true); ui->inputListLineEdit->setEnabled(true); ui->inputListPushButton->setEnabled(true); ui->relativeImageRootLineEdit->setEnabled(false); ui->relativeImageCheckbox->setEnabled(false); ui->relativeImageRootPushButton->setEnabled(false); ui->annotationLineEdit->setEnabled(true); ui->annotationPushButton->setEnabled(true); ui->ImagesLabel->setText("Image folder"); if(!QFile::exists(annotation_file)){ //qCritical() << "Annotation file doesn't exist"; return false; } } if(current_importer == "PascalVOC"){ ui->namesFileLineEdit->setDisabled(true); ui->namesFilePushButton->setDisabled(true); ui->inputListLineEdit->setEnabled(true); ui->inputListPushButton->setEnabled(true); ui->relativeImageRootLineEdit->setEnabled(false); ui->relativeImageCheckbox->setEnabled(false); ui->relativeImageRootPushButton->setEnabled(false); ui->annotationLineEdit->setEnabled(true); ui->annotationPushButton->setEnabled(true); ui->ImagesLabel->setText("Image folder"); if(!QFile::exists(annotation_file)){ //qCritical() << "Annotation file doesn't exist"; return false; } } if(current_importer == "MOT" || ui->importSelectComboBox->currentText() == "BirdsAI"){ ui->namesFileLineEdit->setEnabled(true); ui->namesFilePushButton->setEnabled(true); ui->inputListLineEdit->setEnabled(true); ui->inputListPushButton->setEnabled(true); ui->relativeImageRootLineEdit->setEnabled(false); ui->relativeImageCheckbox->setEnabled(false); ui->relativeImageRootPushButton->setEnabled(false); bool is_mot = (current_importer == "MOT"); ui->annotationLineEdit->setDisabled(is_mot); ui->annotationPushButton->setDisabled(is_mot); if(!QDir(annotation_file).exists() && !is_mot){ //qCritical() << "Annotation folder doesn't exist"; return false; } ui->ImagesLabel->setText("Image folder"); if(!checkNamesFile(names_file)) return false; } if(current_importer == "Darknet"){ ui->namesFileLineEdit->setEnabled(true); ui->namesFilePushButton->setEnabled(true); ui->inputListLineEdit->setEnabled(true); ui->inputListPushButton->setEnabled(true); ui->relativeImageRootLineEdit->setEnabled(true); ui->relativeImageCheckbox->setEnabled(true); ui->relativeImageRootPushButton->setEnabled(true); ui->annotationLineEdit->setDisabled(true); ui->annotationPushButton->setDisabled(true); ui->ImagesLabel->setText("Image list"); if(!checkNamesFile(names_file)) return false; } // If input file exists if(!QFile(input_file).exists() || input_file == ""){ //qCritical() << "Import file/folder doesn't exist"; return false; } ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); return true; } bool ImportDialog::checkNamesFile(QString names_file){ // If we're using darknet, check the names // file exists and contains something if(!QFile::exists(names_file)){ //qCritical() << "Names file doesn't exist"; return false; } QStringList class_list; QFile fh(names_file); if (fh.open(QIODevice::ReadOnly)) { while (!fh.atEnd()) { // Darknet name file is just a newline delimited list of classes QByteArray line = fh.readLine(); class_list.append(line); } } if(class_list.size() == 0){ //qCritical() << "No classes found"; return false; } return true; } void ImportDialog::setImporter(QString format){ if(format == ""){ current_importer = ui->importSelectComboBox->currentText(); settings->setValue("import_format", current_importer); }else{ ui->importSelectComboBox->setCurrentText(format); current_importer = format; } checkOK(); } void ImportDialog::toggleImporter(QString format){ setImporter(format); } ================================================ FILE: src/importdialog.h ================================================ #ifndef IMPORTDIALOG_H #define IMPORTDIALOG_H #include #include #include #include #include #include #include namespace Ui { class ImportDialog; } class ImportDialog : public QDialog { Q_OBJECT public: explicit ImportDialog(QWidget *parent = nullptr); QString getImporter() { return current_importer; } QString getInputFile() { return input_file; } QString getNamesFile() { return names_file; } QString getRelativePath() { return relative_root; } QString getAnnotationFile() { return annotation_file; } bool getImportUnlabelled(); bool getUseRelativePaths() { return relative_image_paths; } ~ImportDialog(); private slots: void setNamesFile(QString path = ""); void setInputFile(QString path = ""); void setAnnotationFile(QString path = ""); void toggleImporter(QString format = ""); void setImportUnlabelled(bool res); void setRelativePaths(bool res); void setRelativeImagePath(QString path = ""); private: bool checkOK(); QSettings *settings; Ui::ImportDialog *ui; QString input_file = ""; QString names_file = ""; QString annotation_file = ""; QString relative_root = ""; QString current_importer = "Darknet"; bool import_unlabelled; bool relative_image_paths; bool checkNamesFile(QString names_file); void setImporter(QString format); }; #endif // IMPORTDIALOG_H ================================================ FILE: src/importdialog.ui ================================================ ImportDialog 0 0 522 274 Dialog Images ... Relative Root ... ... Names file Project Type: true Darknet format BirdsAI Coco Darknet MOT PascalVOC Annotations Images are relative to this path Import unlabelled images true Use relative image paths ... Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() ImportDialog accept() 248 254 157 274 buttonBox rejected() ImportDialog reject() 316 260 286 274 ================================================ FILE: src/importer.h ================================================ #ifndef IMPORTER_H #define IMPORTER_H #include #include #include #include #include #include #endif // IMPORTER_H ================================================ FILE: src/kittiexporter.cpp ================================================ #include "kittiexporter.h" bool KittiExporter::setOutputFolder(QString folder){ if(folder == "") return false; output_folder = folder; train_folder = QDir::cleanPath(output_folder + "/train"); val_folder = QDir::cleanPath(output_folder + "/val"); train_label_folder = QDir::cleanPath(train_folder + "/labels"); train_image_folder = QDir::cleanPath(train_folder + "/images"); val_label_folder = QDir::cleanPath(val_folder + "/labels"); val_image_folder = QDir::cleanPath(val_folder + "/images"); QDir(output_folder).mkpath(train_label_folder); QDir(output_folder).mkpath(train_image_folder); QDir(output_folder).mkpath(val_label_folder); QDir(output_folder).mkpath(val_image_folder); if(!QDir(train_label_folder).exists()) return false; if(!QDir(train_image_folder).exists()) return false; if(!QDir(val_label_folder).exists()) return false; if(!QDir(val_image_folder).exists()) return false; return true; } void KittiExporter::appendLabel(QString label_filename, QList labels, double scale_x, double scale_y){ QFile f(label_filename); if (f.open(QIODevice::WriteOnly | QIODevice::Append)) { BoundingBox label; foreach(label, labels){ QString text; text += label.classname; text += " 0.0"; text += " 0"; text += " 0.0"; text += QString(" %1").arg(label.rect.left() * scale_x); text += QString(" %2").arg(label.rect.top() * scale_x); text += QString(" %3").arg(label.rect.right() * scale_y); text += QString(" %4").arg(label.rect.bottom() * scale_y); text += " 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n"; f.write(text.toUtf8()); } } } int KittiExporter::processSet(QString folder, QList images, int n_images){ int base = 10; int pad = 5; QString image; QList labels; double scale_x=1, scale_y=1; QProgressDialog progress("...", "Abort", 0, images.size(), static_cast(parent())); progress.setWindowModality(Qt::WindowModal); if(disable_progress){ progress.hide(); } int progress_count = 0; foreach(image, images){ if(progress.wasCanceled()){ break; } project->getLabels(image, labels); if(!export_unlabelled && labels.size() == 0){ if(!disable_progress){ progress.setValue(progress_count); progress.setLabelText(QString("%1 is unlabelled").arg(image)); progress.repaint(); QApplication::processEvents(); } continue; } QString extension = QFileInfo(image).suffix(); QString filename_noext = QFileInfo(image).completeBaseName(); QString image_filename = QString("%1/%2.%3").arg(folder).arg(filename_noext).arg(extension); // Correct for duplicate file names in output int dupe_file = 1; while(QFile(image_filename).exists()){ image_filename = QString("%1/%2_%3.%4").arg(folder).arg(filename_noext).arg(dupe_file++).arg(extension); } QString label_filename = QString("%1/labels/%2.txt").arg(folder).arg(n_images, pad, base, QChar('0')); appendLabel(label_filename, labels, scale_x, scale_y); if(!disable_progress){ progress.setValue(progress_count++); progress.setLabelText(image_filename); QApplication::processEvents(); } } return n_images; } void KittiExporter::process(){ int n_images = 0; n_images = processSet(train_folder, train_set, 0); processSet(val_folder, validation_set, n_images); } ================================================ FILE: src/kittiexporter.h ================================================ #ifndef KITTIEXPORTER_H #define KITTIEXPORTER_H #include class KittiExporter : public BaseExporter { Q_OBJECT public: explicit KittiExporter(LabelProject *project, QObject *parent = nullptr) : BaseExporter(project, parent){} public slots: void process(); bool setOutputFolder(QString folder); private: void appendLabel(QString file, QList labels, double scale_x=1, double scale_y=1); int processSet(QString folder, QList images, int i); }; #endif // KITTIEXPORTER_H ================================================ FILE: src/labelproject.cpp ================================================ #include "labelproject.h" LabelProject::LabelProject(QObject *parent) : QObject(parent) { connect(this, SIGNAL(video_split_finished(QString)), this, SLOT(addImageFolder(QString))); } void LabelProject::assignThread(QThread *thread) { this->moveToThread(thread); connect(this, SIGNAL(finished()), thread, SLOT(quit())); connect(this, SIGNAL(finished()), this, SLOT(deleteLater())); connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); thread->start(); } bool LabelProject::loadDatabase(QString fileName) { /*! * Load and check an existing database file. If the database is valid, returns true, otherwise * if an error occured returns false. */ connection_name = fileName; auto db = QSqlDatabase::addDatabase("QSQLITE", connection_name); db.setDatabaseName(fileName); QFileInfo check_file(fileName); if (!db.open()) { QMessageBox::critical(nullptr, QObject::tr("Cannot open database"), QObject::tr("Unable to establish a database connection.\n" "This example needs SQLite support. Please read " "the Qt SQL driver documentation for information how " "to build it.\n\n" "Click Cancel to exit."), QMessageBox::Cancel); return false; } else if ( check_file.exists() && check_file.isFile() ){ return checkDatabase(); }else{ return true; } } bool LabelProject::checkDatabase(){ /*! * Check that the newly loaded database contains the correct tables/fields. Returns * true if the database is valid, false if not. */ { auto db = getDatabase(); QSqlRecord image_record = db.record("images"); QSqlRecord label_record = db.record("labels"); QSqlRecord class_record = db.record("classes"); if(image_record.isEmpty()) return false; if(label_record.isEmpty()) return false; if(class_record.isEmpty()) return false; if(!image_record.contains("image_id")) return false; if(!image_record.contains("path")) return false; if(!label_record.contains("image_id")) return false; if(!label_record.contains("label_id")) return false; if(!label_record.contains("class_id")) return false; if(!label_record.contains("x")) return false; if(!label_record.contains("y")) return false; if(!label_record.contains("width")) return false; if(!label_record.contains("height")) return false; if(!class_record.contains("class_id")) return false; if(!class_record.contains("name")) return false; } qInfo() << "Database structure looks good"; return true; } bool LabelProject::createDatabase(QString fileName) { /*! * Create a new labelling database at the given absolute location (\a fileName). Returns true if the database * was created successfully. */ bool res; loadDatabase(fileName); { auto db = getDatabase(); QSqlQuery query(db); /* * The label database is a simple relational db - image locations, classes * and label bounding boxes. */ res = query.exec("CREATE table images (image_id INTEGER PRIMARY KEY ASC, " "path varchar(256))"); res &= query.exec("CREATE table classes (class_id INTEGER PRIMARY KEY ASC, " "name varchar(32))"); res &= query.exec("CREATE table labels (label_id INTEGER PRIMARY KEY ASC, " "image_id int, class_id int, x int, y int, width int, height int, automatic int)"); if(!res){ qCritical() << "Error: " << query.lastError(); } } return checkDatabase(); } void LabelProject::addFolderRecursive(QString path_filter){ /*! * Search for (and add) all subfolders that match \a path_filter, which * can include * wildcards. */ // Start at the root directory in the path. path_filter = QDir(path_filter).absolutePath(); QRegExp rx(path_filter); rx.setPatternSyntax(QRegExp::Wildcard); // Find the first instance of a * int first_wildcard = path_filter.indexOf('*'); auto pre_wildcard = path_filter.mid(0, first_wildcard); // Get the top level folder int last_separator = pre_wildcard.lastIndexOf(QDir::separator()); auto top_level_folder = pre_wildcard.mid(0, last_separator); // Recurse into this folder and find all subdirectories QDirIterator it(top_level_folder, QDir::Dirs, QDirIterator::Subdirectories); QList subfolders; while (it.hasNext()) { auto subfolder = QDir(it.next()).canonicalPath(); if (rx.exactMatch(subfolder)){ subfolders.append(subfolder); } } subfolders.removeDuplicates(); subfolders.sort(); for(auto &subfolder : subfolders){ addImageFolder(subfolder); } } bool LabelProject::getImageList(QList &images, bool relative) { /*! * Get a list of all images in the database with absolute paths, which is cleared prior to retrieval. Returns false if the database query failed. */ bool res = false; { auto db = getDatabase(); QSqlQuery query(db); res = query.exec("SELECT path FROM images"); if(!res){ qCritical() << "Error: " << query.lastError(); }else{ images.clear(); while (query.next()) { QString path = query.value(0).toString(); // Push absolute file path if(!relative){ auto abs_path = QDir::cleanPath(QDir(db.databaseName()).absolutePath() + QDir::separator() + path); images.push_back(abs_path); }else{ images.push_back(QDir(db.databaseName()).relativeFilePath(path)); } } } } return res; } bool LabelProject::getLabelledImageList(QList &images, bool relative) { /*! * Get a list of all labelled images in the database with absolute paths, which is cleared prior to retrieval. Returns false if the database query failed. */ bool res = false; { auto db = getDatabase(); QSqlQuery query(db); res = query.exec("SELECT path FROM images, labels" " WHERE images.image_id = labels.image_id" " GROUP BY images.image_id"); if(!res){ qCritical() << "Error: " << query.lastError(); }else{ images.clear(); while (query.next()) { QString path = query.value(0).toString(); // Push absolute file path if(!relative){ auto abs_path = QDir::cleanPath(QDir(db.databaseName()).absolutePath() + QDir::separator() + path); images.push_back(abs_path); }else{ images.push_back(QDir(db.databaseName()).relativeFilePath(path)); } } } } return res; } bool LabelProject::getClassList(QList &classes) { /*! * Get a list of all class names in the database and puts them in (\a classes), which is cleared prior to retrieval. Returns false if the database query failed. */ bool res = false; { auto db = getDatabase(); QSqlQuery query(db); res = query.exec("SELECT name FROM classes"); if(!res){ qCritical() << "Error: " << query.lastError(); }else{ classes.clear(); while (query.next()) { QString name = query.value(0).toString(); if(name == ""){ qWarning() << "Warning: empty classname found in db file"; } classes.push_back(name); } } } return res; } bool LabelProject::classInDB(QString className){ /*! * Returns true if \a className is in the database */ bool res = false; { auto db = getDatabase(); QSqlQuery query(db); query.prepare("SELECT * FROM classes WHERe (name)" "= (:name)"); query.bindValue(":name", className); res = query.exec(); if(!res){ qCritical() << "Error: " << query.lastError(); return false; }else{ return query.next(); } } } bool LabelProject::imageInDB(QString fileName){ /*! * Returns true if \a fileName is in the database */ bool res = false; //IF NOT EXISTS(SELECT * FROM images where (path) = (:PATH)) { auto db = getDatabase(); QSqlQuery query(db); query.prepare("SELECT * FROM images WHERe (path)" "= (:path)"); query.bindValue(":path", QDir(db.databaseName()).relativeFilePath(fileName)); res = query.exec(); if(!res){ qCritical() << "Error: " << query.lastError(); }else{ return query.next(); } } return false; } void LabelProject::cancelLoad(){ /*! * Cancel loading a video or processing a folder */ should_cancel = true; } void LabelProject::addVideo(QString fileName, QString outputFolder, int frame_skip){ cv::VideoCapture video(fileName.toStdString()); QString base_name = QFileInfo(fileName).completeBaseName(); QDir dir(outputFolder); cv::Mat frame; int frame_count = 0; int n_frames = video.get(cv::CAP_PROP_FRAME_COUNT); if(!video.isOpened()){ qCritical() << "Failed to open" << fileName; } QProgressDialog progress("...", "Abort", 0, n_frames, static_cast(parent())); progress.setWindowModality(Qt::WindowModal); progress.setWindowTitle("Loading video"); while(video.read(frame)){ if(progress.wasCanceled() || frame.empty()) break; if(frame_count++ % frame_skip != 0) continue; QString output_name = QString("%1_%2.jpg").arg(base_name).arg(frame_count, 6, 10, QChar('0')); output_name = dir.absoluteFilePath(output_name); cv::imwrite(output_name.toStdString(), frame); qDebug() << output_name; progress.setValue(frame_count); progress.setLabelText(output_name); } video.release(); emit video_split_finished(outputFolder); return; } bool LabelProject::addAsset(QString fileName) { /*! * Add an asset to the database, given an absolute path to the image or video (\a fileName). Returns false if the file doesn't exist or if the query failed. */ bool res = false; if(!QFile::exists(fileName)){ qCritical() << "File not found on disk " << fileName; return false; } if(imageInDB(fileName)){ qDebug() << "Image exists!"; return true; } QFileInfo check_file(fileName); if ( check_file.exists() && check_file.isFile() ){ { auto db = getDatabase(); QSqlQuery query(db); query.prepare("INSERT INTO images (path)" "VALUES (:path)"); query.bindValue(":path", QDir(db.databaseName()).relativeFilePath(fileName)); res = query.exec(); if(!res){ qCritical() << "Error: " << query.lastError(); } } } return res; } int LabelProject::getImageId(QString fileName){ /*! * Get the image ID for an image at an absolute path (\a fileName), returns -1 if not found */ int id = -1; { auto db = getDatabase(); QSqlQuery query(db); query.prepare("SELECT image_id FROM images WHERE path = ?"); //Important - we need the relative image path again query.bindValue(0, QDir(db.databaseName()).relativeFilePath(fileName)); bool res = query.exec(); if(!res){ qCritical() << "Error: " << query.lastError(); }else{ if(query.next()){ id = query.value(0).toInt(); } } } return id; } int LabelProject::getClassId(QString className){ /*! * Get the class ID for an class name, (\a className), returns -1 if not found */ int id = -1; { auto db = getDatabase(); QSqlQuery query(db); query.prepare("SELECT class_id FROM classes WHERE name = ?"); query.bindValue(0, className); bool res = query.exec(); if(!res){ qCritical() << "Error: " << query.lastError(); }else{ if(query.next()){ id = query.value(0).toInt(); } } } return id; } QString LabelProject::getClassName(int classID){ /*! * Get the class Name for an class id, (\a classID), returns "" if not found */ QString className = ""; { auto db = getDatabase(); QSqlQuery query(db); query.prepare("SELECT name FROM classes WHERE class_id = ?"); query.bindValue(0, classID); bool res = query.exec(); if(!res){ qCritical() << "Error: " << query.lastError(); }else{ if(query.next()){ className = query.value(0).toString(); } } } return className; } bool LabelProject::getLabels(QString fileName, QList &bboxes){ bboxes.clear(); int image_id = getImageId(fileName); return getLabels(image_id, bboxes); } bool LabelProject::getClassCounts(QMap &counts){ /*! * Get class counts for the project. */ bool res = false; { auto db = getDatabase(); QSqlQuery query(db); query.prepare("SELECT class_id, COUNT(class_id) AS \"count\" FROM labels GROUP BY class_id"); res = query.exec(); if(!res){ qCritical() << "Error: " << query.lastError(); } while(query.next()){ auto rec = query.record(); auto id = rec.value(rec.indexOf("class_id")).toInt(); auto count = rec.value(rec.indexOf("count")).toInt(); counts.insert(id, count); } } return res; } bool LabelProject::getLabels(int image_id, QList &bboxes){ /*! * Get the labels for a given image with ID \a image_id and puts them in the provided list: \a bboxes. Note \a bboxes will be emptied. * Returns false if the query failed. */ bool res = false; if(image_id > 0){ { auto db = getDatabase(); QSqlQuery query(db); query.prepare("SELECT label_id, name, x, y, width, height FROM labels" " INNER JOIN classes ON labels.class_id = classes.class_id" " WHERE image_id = ?"); query.addBindValue(image_id); res = query.exec(); if(!res){ qCritical() << "Error: " << query.lastError(); } while(query.next()){ BoundingBox new_bbox; auto rec = query.record(); new_bbox.label_id = rec.value(rec.indexOf("label_id")).toInt(); new_bbox.classname = rec.value(rec.indexOf("name")).toString(); new_bbox.classid = getClassId(new_bbox.classname); new_bbox.rect.setX(rec.value(rec.indexOf("x")).toInt()); new_bbox.rect.setY(rec.value(rec.indexOf("y")).toInt()); new_bbox.rect.setWidth(rec.value(rec.indexOf("width")).toInt()); new_bbox.rect.setHeight(rec.value(rec.indexOf("height")).toInt()); if (new_bbox.rect.width() * new_bbox.rect.height() <= 0) { qWarning() << "Zero size bounding box found in database"; continue; } bboxes.append(new_bbox); } } } return res; } bool LabelProject::removeLabels(QString fileName){ /*! * Remove all labels from an image given an absolute path to the image (\a fileName). */ int image_id = getImageId(fileName); bool res = false; if(image_id > 0){ { auto db = getDatabase(); QSqlQuery query(db); query.prepare("DELETE FROM labels WHERE (image_id = :image_id)"); query.bindValue(":image_id", image_id); res = query.exec(); if(!res){ qCritical() << "Error: " << query.lastError(); } } } return res; } bool LabelProject::removeLabel(QString fileName, int label_id) { /*! * Remove a label given an absolute path (\a fileName) and the bounding box (\a bbox). Returns false * if the query failed. */ int image_id = getImageId(fileName); bool res = false; if (image_id > 0) { { auto db = getDatabase(); QSqlQuery query(db); query.prepare( "DELETE FROM labels WHERE (image_id = :image_id AND label_id = :label_id)"); query.bindValue(":image_id", image_id); query.bindValue(":label_id", label_id); res = query.exec(); if(!res){ qCritical() << "Error: " << query.lastError(); } } } return res; } bool LabelProject::setOccluded(QString fileName, BoundingBox bbox, int occluded){ /*! * Set a label to be occluded. Returns false * if the query failed. */ int image_id = getImageId(fileName); int class_id = getClassId(bbox.classname); bool res = false; if(image_id > 0 && class_id > 0){ { auto db = getDatabase(); QSqlQuery query(db); query.prepare("UPDATE labels SET occluded = :occluded WHERE (image_id = :image_id AND class_id = :class_id" " AND x = :x AND y = :y AND width = :width AND height = :height)"); query.bindValue(":image_id", image_id); query.bindValue(":class_id", class_id); query.bindValue(":x", bbox.rect.x()); query.bindValue(":y", bbox.rect.y()); query.bindValue(":width", bbox.rect.width()); query.bindValue(":height", bbox.rect.height()); query.bindValue(":occluded", occluded); res = query.exec(); if(!res){ qCritical() << "Error: " << query.lastError(); } } } return res; } bool LabelProject::removeClass(QString className){ /*! * Remove a class given a class name (\a className). Also removes all labels with that class. Returns false * if the query failed. */ int class_id = getClassId(className); bool res = false; if(class_id > 0){ { auto db = getDatabase(); QSqlQuery query(db); // Delete all labels with this class query.prepare("DELETE FROM labels WHERE (class_id = :class_id)"); query.bindValue(":class_id", class_id); res = query.exec(); if(!res){ qCritical() << "Error: " << query.lastError(); } // Delete the class itself query.prepare("DELETE FROM classes WHERE (class_id = :class_id)"); query.bindValue(":class_id", class_id); res = query.exec(); if(!res){ qCritical() << "Error: " << query.lastError(); } } } return res; } int LabelProject::getNextUnlabelled(QString fileName){ /*! * Returns the index of the next unlabelled image, after \a fileName */ QList images; getImageList(images); QList bboxes; for(int i = images.indexOf(fileName) + 1; i < images.size(); i++){ bboxes.clear(); getLabels(images.at(i), bboxes); if(bboxes.size() == 0) return i+1; } return -1; } int LabelProject::getNextInstance(QString fileName, QString className){ /*! * Returns the index of the next unlabelled image, after \a fileName */ QList images; getImageList(images); int i = images.indexOf(fileName); QList bboxes; for(i += 1; i < images.size(); i++){ bboxes.clear(); getLabels(images.at(i), bboxes); for(auto bbox : bboxes){ if(bbox.classname.compare(className) == 0){ return i; } } } return -1; } bool LabelProject::removeImage(QString fileName){ /*! * Remove an image given an absolute path (\a fileName). Also removes all labels for that image. Returns false * if the query failed. */ int image_id = getImageId(fileName); bool res = false; if(image_id > 0){ { auto db = getDatabase(); QSqlQuery query(db); // Delete all labels for this image query.prepare("DELETE FROM labels WHERE (image_id = :image_id)"); query.bindValue(":image_id", image_id); res = query.exec(); if(!res){ qCritical() << "Error: " << query.lastError(); } // Delete the image itself query.prepare("DELETE FROM images WHERE (image_id = :image_id)"); query.bindValue(":image_id", image_id); res = query.exec(); if(!res){ qCritical() << "Error: " << query.lastError(); } } } return res; } bool LabelProject::updateLabel(QString fileName, int labelID, BoundingBox new_bbox) { /*! * Update a label given an absolute path (\a fileName), the old label ID (\a labelID) * and a new bounding box (\a new_bbox). Returns false if the query failed. */ QMutexLocker locker(&mutex); bool res = false; int image_id = getImageId(fileName); { auto db = getDatabase(); db.transaction(); if (labelID > 0 && image_id > 0 && new_bbox.label_id > 0 && new_bbox.rect.width() * new_bbox.rect.height() > 0) { QSqlQuery query(db); query.prepare("UPDATE labels SET width = (:width)," " height = (:height), " " class_id = (:class_id), " " x = (:x), " " y = (:y) " " WHERE labels.label_id = (:label_id)"); query.bindValue(":class_id", new_bbox.classid); query.bindValue(":x", new_bbox.rect.x()); query.bindValue(":y", new_bbox.rect.y()); query.bindValue(":width", new_bbox.rect.width()); query.bindValue(":height", new_bbox.rect.height()); query.bindValue(":label_id", labelID); res = query.exec(); if (!res) { qCritical() << "Error updating label: " << query.lastError(); } } db.commit(); return res; } } bool LabelProject::addLabel(QString fileName, BoundingBox bbox) { /*! * Add a label given an absolute path (\a fileName) and the bounding box (\a bbox). Returns false * if the query failed. */ QMutexLocker locker(&mutex); bool res = false; int image_id = getImageId(fileName); int class_id = -1; if (bbox.classname != "") { class_id = getClassId(bbox.classname); } else if (bbox.classid > 0) { class_id = bbox.classid; } if (image_id > 0 && class_id > 0 && bbox.rect.width() * bbox.rect.height() > 0) { { auto db = getDatabase(); QSqlQuery query(db); query.prepare("INSERT INTO labels (image_id, class_id, x, y, width, height)" "VALUES (:image_id, :class_id, :x, :y, :width, :height)"); query.bindValue(":image_id", image_id); query.bindValue(":class_id", class_id); query.bindValue(":x", bbox.rect.x()); query.bindValue(":y", bbox.rect.y()); query.bindValue(":width", bbox.rect.width()); query.bindValue(":height", bbox.rect.height()); res = query.exec(); if (!res) { qCritical() << "Error: " << query.lastError(); } } } return res; } bool LabelProject::addLabel(QString fileName, QList bboxes) { /*! * Add a label given an absolute path (\a fileName) and the bounding box (\a bbox). Returns false * if the query failed. */ QMutexLocker locker(&mutex); bool res = false; int image_id = getImageId(fileName); int class_id = -1; { auto db = getDatabase(); db.transaction(); for (auto bbox : bboxes) { if (bbox.classname != "") { class_id = getClassId(bbox.classname); } else if (bbox.classid > 0) { class_id = bbox.classid; } if (image_id > 0 && class_id > 0 && bbox.rect.width() * bbox.rect.height() > 0) { QSqlQuery query(db); query.prepare("INSERT INTO labels (image_id, class_id, x, y, width, height)" "VALUES (:image_id, :class_id, :x, :y, :width, :height)"); query.bindValue(":image_id", image_id); query.bindValue(":class_id", class_id); query.bindValue(":x", bbox.rect.x()); query.bindValue(":y", bbox.rect.y()); query.bindValue(":width", bbox.rect.width()); query.bindValue(":height", bbox.rect.height()); res = query.exec(); if (!res) { qCritical() << "Error: " << query.lastError(); } } } db.commit(); } return res; } int LabelProject::addImageFolder(QString path) { /*! * Add all images in a folder given an absolute \a path to the directory. Returns the number of images successfully added. */ QDir dir(path); int number_added = 0; if (dir.exists()) { QStringList filters; filters << "*.png" << "*.jpg" << "*.jpeg" << "*.bmp" << "*.tiff"; auto image_list = dir.entryInfoList(filters, QDir::Files | QDir::NoDotAndDotDot); QFileInfo image_info; QSqlDatabase::database().transaction(); QProgressDialog progress("...", "Abort", 0, image_list.size(), static_cast(parent())); progress.setWindowModality(Qt::WindowModal); progress.setWindowTitle("Loading images"); int i = 0; foreach (image_info, image_list) { if (progress.wasCanceled()) { break; } QString image_path = image_info.absoluteFilePath(); bool res = addAsset(image_path); if (res) { number_added++; qDebug() << "Added image: " << image_path; } else { qCritical() << "Failed to add image: " << image_path; } progress.setValue(i++); progress.setLabelText(image_path); QApplication::processEvents(); } QSqlDatabase::database().commit(); } emit load_finished(); return number_added; } bool LabelProject::addLabelledAssets(QList images, QList> bboxes) { if (images.size() != bboxes.size()) return false; QProgressDialog progress("...", "Abort", 0, images.size(), static_cast(parent())); progress.setWindowModality(Qt::WindowModal); progress.setWindowTitle("Loading into database"); for (int i = 0; i < images.size(); ++i) { if (progress.wasCanceled()) break; auto image = images[i]; if (addAsset(image)) { addLabel(image, bboxes[i]); } progress.setValue(i); progress.setLabelText(QString("%1/%2: %3").arg(i).arg(images.size()).arg(image)); } return true; } bool LabelProject::addClass(QString className) { /*! * Add a class with name \a className. Returns false * if the query failed. */ bool res = false; // Make sure we strip any extraneous characters className = className.simplified(); if (classInDB(className)) { qWarning() << "Class " << className << "exists!"; return true; } { auto db = getDatabase(); QSqlQuery query(db); query.prepare("INSERT INTO classes (name)" "VALUES (:name)"); query.bindValue(":name", className); res = query.exec(); if (!res) { qCritical() << "Error: " << query.lastError(); } } return res; } QSqlDatabase LabelProject::getDatabase() { return QSqlDatabase::database(connection_name); } LabelProject::~LabelProject() { /*! * Destructor, closes the database if it's open. */ QSqlDatabase::removeDatabase(connection_name); emit finished(); } ================================================ FILE: src/labelproject.h ================================================ #ifndef LABELPROJECT_H #define LABELPROJECT_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class LabelProject : public QObject { Q_OBJECT public: explicit LabelProject(QObject *parent = nullptr); ~LabelProject(); bool loadDatabase(QString fileName); bool createDatabase(QString fileName); bool addClass(QString className); bool getClassList(QList &classes); bool getClassCounts(QMap &counts); bool removeClass(QString className); bool classInDB(QString classname); bool addAsset(QString fileName); bool addLabelledAssets(QList images, QList> bboxes); void addVideo(QString fileName, QString outputFolder, int frame_skip=1); bool getImageList(QList &images, bool relative=false); bool getLabelledImageList(QList &images, bool relative=false); bool removeImage(QString fileName); bool imageInDB(QString fileName); bool addLabel(QString fileName, BoundingBox bbox); bool addLabel(QString fileName, QList bbox); bool getLabels(QString fileName, QList &bboxes); bool getLabels(int imageId, QList &bboxes); bool removeLabel(QString fileName, int labelID); bool removeLabels(QString fileName); bool updateLabel(QString fileName, int labelID, BoundingBox new_bbox); bool setOccluded(QString fileName, BoundingBox bbox, int occluded); int getNextUnlabelled(QString fileName); int getNextInstance(QString fileName, QString className); QDir getDbFolder(){ auto db = getDatabase(); return QDir(db.databaseName()); } int getImageId(QString fileName); int getClassId(QString className); QString getClassName(int classID); void assignThread(QThread* thread); signals: void finished(); bool labelUpdated(BoundingBox selected_bbox, BoundingBox new_bbox); void video_split_finished(QString); void load_finished(); void load_progress(int); public slots: int addImageFolder(QString path); void cancelLoad(); void addFolderRecursive(QString path_filter); private: QMutex mutex; bool checkDatabase(); bool should_cancel; QString connection_name; QSqlDatabase getDatabase(); }; #endif // LABELPROJECT_H ================================================ FILE: src/labelrefinedialog.cpp ================================================ #include "labelrefinedialog.h" #include "ui_labelrefinedialog.h" LabelRefineDialog::LabelRefineDialog(QWidget *parent) : QDialog(parent), ui(new Ui::LabelRefineDialog) { ui->setupUi(this); } LabelRefineDialog::~LabelRefineDialog() { delete ui; } ================================================ FILE: src/labelrefinedialog.h ================================================ #ifndef LABELREFINEDIALOG_H #define LABELREFINEDIALOG_H #include namespace Ui { class LabelRefineDialog; } class LabelRefineDialog : public QDialog { Q_OBJECT public: explicit LabelRefineDialog(QWidget *parent = nullptr); ~LabelRefineDialog(); private: Ui::LabelRefineDialog *ui; }; #endif // LABELREFINEDIALOG_H ================================================ FILE: src/labelrefinedialog.ui ================================================ LabelRefineDialog 0 0 884 533 Dialog 0 0 background:#eeeeee TextLabel 0 0 Box Properties Class: px Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok px px px Left Bottom Right Top px 20 Display padding Qt::Vertical 20 40 Qt::Vertical 20 40 Image / Box Image ID / 0 Label ID / 0 Previous Next Qt::Vertical 20 40 Previous Next 24 Image Name buttonBox accepted() LabelRefineDialog accept() 248 254 157 274 buttonBox rejected() LabelRefineDialog reject() 316 260 286 274 ================================================ FILE: src/main.cpp ================================================ #include "mainwindow.h" #include "cliparser.h" #include int main(int argc, char *argv[]) { QCoreApplication::setApplicationName("deeplabel"); QCoreApplication::setApplicationVersion("0.15"); QApplication a(argc, argv); if(argc == 1){ MainWindow w; w.show(); return a.exec(); }else{ CliParser cli; auto res = cli.Run(); if(!res){ return 1; } return 0; } } ================================================ FILE: src/mainwindow.cpp ================================================ #include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); connect(ui->actionNew_Project, SIGNAL(triggered(bool)), this, SLOT(newProject())); connect(ui->actionOpen_Project, SIGNAL(triggered(bool)), this, SLOT(openProject())); connect(ui->actionMerge_Project, SIGNAL(triggered(bool)), this, SLOT(mergeProject())); connect(ui->actionAdd_video, SIGNAL(triggered(bool)), this, SLOT(addVideo())); connect(ui->actionAdd_image, SIGNAL(triggered(bool)), this, SLOT(addImages())); connect(ui->actionAdd_image_folder, SIGNAL(triggered(bool)), this, SLOT(addImageFolder())); connect(ui->actionAdd_image_folders, SIGNAL(triggered(bool)), this, SLOT(addImageFolders())); connect(ui->actionNextImage, SIGNAL(triggered(bool)), this, SLOT(nextImage())); connect(ui->actionPreviousImage, SIGNAL(triggered(bool)), this, SLOT(previousImage())); connect(ui->actionJump_forward, SIGNAL(triggered(bool)), this, SLOT(jumpForward())); connect(ui->actionJump_backward, SIGNAL(triggered(bool)), this, SLOT(jumpBackward())); connect(ui->addClassButton, SIGNAL(clicked(bool)), this, SLOT(addClass())); connect(ui->newClassText, SIGNAL(editingFinished()), this, SLOT(addClass())); connect(ui->actionInit_Tracking, SIGNAL(triggered(bool)), this, SLOT(initTrackers())); connect(ui->actionPropagate_Tracking, SIGNAL(triggered(bool)), this, SLOT(updateTrackers())); connect(ui->propagateCheckBox, SIGNAL(clicked(bool)), this, SLOT(toggleAutoPropagate(bool))); connect(ui->refineTrackingCheckbox, SIGNAL(clicked(bool)), this, SLOT(toggleRefineTracking(bool))); connect(ui->nextUnlabelledButton, SIGNAL(clicked(bool)), this, SLOT(nextUnlabelled())); connect(ui->nextInstanceButton, SIGNAL(clicked(bool)), this, SLOT(nextInstance())); display = new ImageDisplay; ui->imageDisplayLayout->addWidget(display); currentImage = display->getImageLabel(); connect(this, SIGNAL(selectedClass(QString)), currentImage, SLOT(setClassname(QString))); connect(currentImage, SIGNAL(newLabel(BoundingBox)), this, SLOT(addLabel(BoundingBox))); connect(currentImage, SIGNAL(removeLabel(BoundingBox)), this, SLOT(removeLabel(BoundingBox))); connect(currentImage, SIGNAL(updateLabel(BoundingBox, BoundingBox)), this, SLOT(updateLabel(BoundingBox, BoundingBox))); connect(currentImage, SIGNAL(setCurrentClass(QString)), this, SLOT(setCurrentClass(QString))); connect(ui->actionDraw_Tool, SIGNAL(triggered(bool)), currentImage, SLOT(setDrawMode())); connect(ui->actionSelect_Tool, SIGNAL(triggered(bool)), currentImage, SLOT(setSelectMode())); connect(ui->classComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(setCurrentClass(QString))); connect(display, SIGNAL(image_loaded()), this, SLOT(updateImageInfo())); connect(ui->removeClassButton, SIGNAL(clicked(bool)), this, SLOT(removeClass())); connect(ui->removeImageButton, SIGNAL(clicked(bool)), this, SLOT(removeImage())); connect(ui->removeImageLabelsButton, SIGNAL(clicked(bool)), this, SLOT(removeImageLabels())); connect(ui->actionRemove_labels_forwards, SIGNAL(triggered(bool)), this, SLOT(removeImageLabelsForward())); ui->actionDraw_Tool->setChecked(true); connect(ui->changeImageButton, SIGNAL(clicked(bool)), this, SLOT(updateDisplay())); connect(ui->imageNumberSpinbox, SIGNAL(editingFinished()), this, SLOT(updateDisplay())); connect(ui->colourMapCombo, SIGNAL(currentIndexChanged(QString)), display, SLOT(setColourMap(QString))); connect(ui->colourMapCheckbox, SIGNAL(clicked(bool)), display, SLOT(toggleColourMap(bool))); connect(ui->actionWrap_images, SIGNAL(triggered(bool)), this, SLOT(enableWrap(bool))); connect(ui->actionExport, SIGNAL(triggered(bool)), this, SLOT(launchExportDialog())); connect(ui->actionImport_Labels, SIGNAL(triggered(bool)), this, SLOT(launchImportDialog())); connect(ui->actionRefine_boxes, SIGNAL(triggered(bool)), this, SLOT(refineBoxes())); connect(ui->actionSetup_detector, SIGNAL(triggered(bool)), this, SLOT(setupDetector())); connect(ui->actionCalculate_histograms, SIGNAL(triggered(bool)), this, SLOT(computeStatistics())); auto prev_shortcut = ui->actionPreviousImage->shortcuts(); prev_shortcut.append(QKeySequence("Left")); ui->actionPreviousImage->setShortcuts(prev_shortcut); auto next_shortcut = ui->actionNextImage->shortcuts(); next_shortcut.append(QKeySequence("Right")); ui->actionNextImage->setShortcuts(next_shortcut); // Override progress bar animation on Windows #ifdef WIN32 ui->imageProgressBar->setStyleSheet("QProgressBar::chunk {background-color: #3add36; width: 1px;}"); #endif project = new LabelProject; settings = new QSettings("DeepLabel", "DeepLabel"); multitracker = new MultiTrackerCV(); reinterpret_cast(multitracker)->setTrackerType(CSRT); QtAwesome* awesome = new QtAwesome(qApp); awesome->initFontAwesome(); QVariantMap options; options.insert( "color" , QColor(30,30,30) ); options.insert( "scale-factor", 0.7 ); ui->actionPreviousImage->setIcon(awesome->icon(fa::arrowleft, options)); ui->actionNextImage->setIcon(awesome->icon(fa::arrowright, options)); ui->actionSelect_Tool->setIcon(awesome->icon(fa::handpointero, options)); ui->actionDraw_Tool->setIcon(awesome->icon(fa::pencilsquareo, options)); ui->actionDetect_Objects->setIcon(awesome->icon(fa::magic, options)); ui->actionDetect_Objects->setEnabled(false); connect(ui->actionDetect_Objects, SIGNAL(triggered(bool)), this, SLOT(detectCurrentImage())); connect(ui->actionSet_threshold, SIGNAL(triggered(bool)), this, SLOT(setConfidenceThreshold())); connect(ui->actionSet_NMS_threshold, SIGNAL(triggered(bool)), this, SLOT(setNMSThreshold())); detector.setConfidenceThreshold(settings->value("detector_confidence", 0.5).toDouble()); detector.setNMSThreshold(settings->value("detector_nms_threshold", 0.4).toDouble()); connect(ui->actionDetect_project, SIGNAL(triggered(bool)), this, SLOT(detectProject())); //ui->actionInit_Tracking->setIcon(awesome->icon(fa::objectungroup, options)); refine_range_dialog = new RefineRangeDialog(this); connect(ui->actionRefine_image_range, SIGNAL(triggered(bool)), refine_range_dialog, SLOT(open())); connect(refine_range_dialog, SIGNAL(accepted()), this, SLOT(handleRefineRange())); resize(QGuiApplication::primaryScreen()->availableSize() * 3 / 5); } void MainWindow::mergeProject(QString filename){ if(filename == ""){ QString openDir = settings->value("project_folder", QDir::homePath()).toString(); filename = QFileDialog::getOpenFileName(this, tr("Open Project"), openDir, tr("Label database (*.lbldb)")); } if(filename == "") return; LabelProject new_project; new_project.loadDatabase(filename); // Add new classes QList new_classes; new_project.getClassList(new_classes); qInfo() << "Found " << new_classes.size() << " classes."; for(auto &classname : new_classes){ project->addClass(classname); } // Add new images QList new_images; new_project.getImageList(new_images); qInfo() << "Found " << new_images.size() << " images."; for(auto &image : new_images){ // Add image auto res = project->addAsset(image); if(!res){ qWarning() << "Problem adding: " << image; }else{ qDebug() << "Added: " << image; } // Add labels for image QList bboxes; new_project.getLabels(image, bboxes); for(auto &bbox : bboxes){ // Update the class ID bbox.classid = project->getClassId(bbox.classname); project->addLabel(image, bbox); } } updateImageList(); updateClassList(); updateDisplay(); } void MainWindow::setCurrentClass(QString name){ if(ui->classComboBox->currentText() != name){ ui->classComboBox->setCurrentText(name); } current_class = name; emit selectedClass(current_class); } void MainWindow::setupDetector(void){ ui->actionDetect_Objects->setEnabled(false); DetectorSetupDialog detection_dialog; detection_dialog.exec(); if(detection_dialog.result() != QDialog::Accepted ) return; auto names_file = detection_dialog.getNames().toStdString(); auto cfg_file = detection_dialog.getCfg().toStdString(); auto weight_file = detection_dialog.getWeights().toStdString(); detector.setChannels(detection_dialog.getChannels()); detector.setTarget(detection_dialog.getTarget()); detector.setFramework(detection_dialog.getFramework()); detector.setConvertGrayscale(detection_dialog.getConvertGrayscale()); detector.setConvertDepth(detection_dialog.getConvertDepth()); detector.setImageSize(detection_dialog.getWidth(), detection_dialog.getHeight()); detector.loadNetwork(names_file, cfg_file, weight_file); ui->actionDetect_Objects->setEnabled(true); ui->actionDetect_project->setEnabled(true); } void MainWindow::detectCurrentImage(){ auto image = display->getOriginalImage(); detectObjects(image, current_imagepath); updateClassList(); updateLabels(); } void MainWindow::detectObjects(cv::Mat &image, QString image_path){ if(image.empty()) return; auto new_boxes = detector.infer(image); QList existing_boxes; project->getLabels(image_path, existing_boxes); for(auto &box : new_boxes){ if(!project->classInDB(box.classname)){ project->addClass(box.classname); } // Strip out boxes which are already in the image // assume detector is deterministic bool exists = false; for(auto &existing : existing_boxes){ if(existing.rect == box.rect && existing.classname == box.classname){ exists = true; } } if(!exists){ qDebug() << "Adding label"; project->addLabel(image_path, box); } } } void MainWindow::setConfidenceThreshold(void){ QDialog confidence_set_dialog(this); auto threshold_spinbox = new QDoubleSpinBox(); threshold_spinbox->setMinimum(0); threshold_spinbox->setMaximum(1); threshold_spinbox->setValue(detector.getConfidenceThreshold()); auto threshold_label = new QLabel("Detection Threshold: "); auto ok_button = new QPushButton("Ok"); confidence_set_dialog.setWindowTitle("Confidence Threshold"); confidence_set_dialog.setLayout(new QVBoxLayout()); confidence_set_dialog.layout()->addWidget(threshold_label); confidence_set_dialog.layout()->addWidget(threshold_spinbox); confidence_set_dialog.layout()->addWidget(ok_button); confidence_set_dialog.layout()->setSizeConstraint(QLayout::SetFixedSize); connect(ok_button, SIGNAL(clicked(bool)), &confidence_set_dialog, SLOT(accept())); confidence_set_dialog.exec(); if(confidence_set_dialog.result() == QDialog::Accepted){ detector.setConfidenceThreshold(threshold_spinbox->value()); settings->setValue("detector_confidence", detector.getConfidenceThreshold()); } } void MainWindow::setNMSThreshold(void){ QDialog confidence_set_dialog(this); auto threshold_spinbox = new QDoubleSpinBox(); threshold_spinbox->setMinimum(0); threshold_spinbox->setMaximum(1); threshold_spinbox->setValue(detector.getNMSThreshold()); auto threshold_label = new QLabel("NMS Threshold: "); auto ok_button = new QPushButton("Ok"); confidence_set_dialog.setWindowTitle("NMS Threshold"); confidence_set_dialog.setLayout(new QVBoxLayout()); confidence_set_dialog.layout()->addWidget(threshold_label); confidence_set_dialog.layout()->addWidget(threshold_spinbox); confidence_set_dialog.layout()->addWidget(ok_button); confidence_set_dialog.layout()->setSizeConstraint(QLayout::SetFixedSize); connect(ok_button, SIGNAL(clicked(bool)), &confidence_set_dialog, SLOT(accept())); confidence_set_dialog.exec(); if(confidence_set_dialog.result() == QDialog::Accepted){ detector.setNMSThreshold(threshold_spinbox->value()); settings->setValue("detector_nms_threshold", detector.getNMSThreshold()); } } void MainWindow::detectProject(void){ QProgressDialog progress("Running detector", "Abort", 0, images.size(), this); progress.setWindowModality(Qt::WindowModal); progress.setLabelText("..."); int i = 0; for(auto& image_path : images){ progress.setLabelText(image_path); if (progress.wasCanceled()) break; auto image = cv::imread(image_path.toStdString(), cv::IMREAD_UNCHANGED|cv::IMREAD_ANYDEPTH); // Assume we have an alpha image if 4 channels if(image.channels() == 4){ cv::cvtColor(image, image, cv::COLOR_BGRA2BGR); } detectObjects(image, image_path); progress.setValue(i++); } updateClassList(); updateLabels(); } void MainWindow::toggleAutoPropagate(bool state){ track_previous = state; } void MainWindow::toggleRefineTracking(bool state){ refine_on_propagate = state; } void MainWindow::enableWrap(bool enable){ wrap_index = enable; } void MainWindow::jumpForward(int n){ if(ui->imageNumberSpinbox->maximum() == 0) return; current_index = std::min(ui->imageNumberSpinbox->maximum()-1, ui->imageNumberSpinbox->value()+n); ui->imageNumberSpinbox->setValue(current_index); updateDisplay(); } void MainWindow::jumpBackward(int n){ current_index = std::max(1, ui->imageNumberSpinbox->value()-n); ui->imageNumberSpinbox->setValue(current_index); updateDisplay(); } void MainWindow::setDrawMode(){ ui->actionDraw_Tool->setChecked(true); ui->actionSelect_Tool->setChecked(false); currentImage->setDrawMode(); } void MainWindow::setSelectMode(){ ui->actionDraw_Tool->setChecked(false); ui->actionSelect_Tool->setChecked(true); currentImage->setSelectMode(); } void MainWindow::openProject(QString fileName) { if(fileName == ""){ QString openDir = settings->value("project_folder", QDir::homePath()).toString(); fileName = QFileDialog::getOpenFileName(this, tr("Open Project"), openDir, tr("Label database (*.lbldb)")); } if(fileName != ""){ settings->setValue("project_folder", QFileInfo(fileName).absoluteDir().absolutePath()); if(project->loadDatabase(fileName)){ initDisplay(); ui->menuImages->setEnabled(true); ui->menuDetection->setEnabled(true); ui->menuLabeling->setEnabled(true); ui->menuNavigation->setEnabled(true); ui->mainToolBar->setEnabled(true); ui->actionImport_Labels->setEnabled(true); ui->actionMerge_Project->setEnabled(true); setWindowTitle("DeepLabel - " + fileName); }else{ QMessageBox::warning(this,tr("Project file error"), tr("Failed to open project.")); setWindowTitle("DeepLabel"); } } return; } void MainWindow::updateLabels(){ QList bboxes; project->getLabels(current_imagepath, bboxes); ui->instanceCountLabel->setNum(static_cast(bboxes.size())); currentImage->setBoundingBoxes(bboxes); } void MainWindow::addImageFolders(void){ QDialog image_folder_dialog(this); auto path_edit = new QLineEdit(); auto ok_button = new QPushButton("Ok"); auto path_label = new QLabel("Folder path (wildcards allowed)"); image_folder_dialog.setWindowTitle("Add folders"); image_folder_dialog.setLayout(new QVBoxLayout()); image_folder_dialog.layout()->addWidget(path_label); image_folder_dialog.layout()->addWidget(path_edit); image_folder_dialog.layout()->addWidget(ok_button); connect(ok_button, SIGNAL(clicked(bool)), &image_folder_dialog, SLOT(accept())); image_folder_dialog.exec(); if(image_folder_dialog.result() == QDialog::Accepted){ project->addFolderRecursive(path_edit->text()); } } void MainWindow::updateImageList(){ project->getImageList(images); number_images = images.size(); if(number_images == 0){ ui->imageGroupBox->setDisabled(true); ui->labelGroupBox->setDisabled(true); ui->navigationGroupBox->setDisabled(true); ui->actionExport->setDisabled(true); ui->imageIndexLabel->setText(QString("-")); }else{ ui->imageGroupBox->setEnabled(true); ui->labelGroupBox->setEnabled(true); ui->navigationGroupBox->setEnabled(true); ui->actionExport->setEnabled(true); } ui->imageProgressBar->setValue(0); ui->imageProgressBar->setMaximum(number_images); ui->imageNumberSpinbox->setMaximum(number_images); ui->imageNumberSpinbox->setValue(1); refine_range_dialog->setMaxImage(number_images); } void MainWindow::updateClassList(){ project->getClassList(classes); ui->classComboBox->clear(); QString classname; foreach(classname, classes){ if(classname != "") ui->classComboBox->addItem(classname); } if(classes.size() > 0){ ui->classComboBox->setEnabled(true); ui->removeClassButton->setEnabled(true); ui->classComboBox->setCurrentIndex(0); }else{ ui->classComboBox->setDisabled(true); ui->removeClassButton->setDisabled(true); } } void MainWindow::addClass(){ QString new_class = ui->newClassText->text(); if(new_class.simplified() != "" && !classes.contains(new_class)){ project->addClass(new_class.simplified()); ui->newClassText->clear(); updateClassList(); setCurrentClass(new_class.simplified()); } } void MainWindow::addLabel(BoundingBox bbox){ project->addLabel(current_imagepath, bbox); updateLabels(); } void MainWindow::removeLabel(BoundingBox bbox){ project->removeLabel(current_imagepath, bbox.label_id); updateLabels(); } void MainWindow::removeImageLabels(){ if (QMessageBox::Yes == QMessageBox::question(this, tr("Remove Labels"), QString("Really delete all labels for this image?"))){; project->removeLabels(current_imagepath); updateLabels(); updateDisplay(); } } void MainWindow::removeImageLabelsForward(){ if (QMessageBox::Yes == QMessageBox::question(this, tr("Remove Labels"), QString("Really delete all labels forwards?"))){; while(true){ QList bboxes; project->getLabels(current_imagepath, bboxes); if(bboxes.size() == 0){ return; } if(current_index == (number_images-1)){ return; }else{ current_index++; } ui->imageNumberSpinbox->setValue(current_index+1); project->removeLabels(current_imagepath); // Show the new image updateLabels(); updateDisplay(); } } } void MainWindow::updateLabel(BoundingBox old_bbox, BoundingBox new_bbox) { project->updateLabel(current_imagepath, old_bbox.label_id, new_bbox); updateLabels(); } void MainWindow::removeImage(){ if (QMessageBox::Yes == QMessageBox::question(this, tr("Remove Image"), tr("Really delete image and associated labels?"))){ auto previousProgressValue = ui->imageProgressBar->value(); auto previousSpinboxValue = ui->imageNumberSpinbox->value(); project->removeImage(current_imagepath); updateImageList(); ui->imageProgressBar->setValue(MIN(previousProgressValue, ui->imageProgressBar->maximum())); ui->imageNumberSpinbox->setValue(MIN(previousSpinboxValue, ui->imageNumberSpinbox->maximum())); updateDisplay(); } } void MainWindow::removeClass(){ if (QMessageBox::Yes == QMessageBox::question(this, tr("Remove Class"), QString("Really delete all \"%1\" labels from your entire dataset?") .arg(current_class))){; project->removeClass(current_class); updateClassList(); updateDisplay(); } } void MainWindow::initDisplay(){ display->clearPixmap(); updateImageList(); updateClassList(); current_index = 0; updateDisplay(); } void MainWindow::nextUnlabelled(){ int n = project->getNextUnlabelled(current_imagepath); if(n != -1){ ui->imageNumberSpinbox->setValue(n); updateDisplay(); } } void MainWindow::nextInstance(void){ int n = project->getNextInstance(current_imagepath, current_class); if(n != -1){ ui->imageNumberSpinbox->setValue(n+1); updateDisplay(); } } QRect MainWindow::refineBoundingBoxSimple(cv::Mat image, QRect bbox, int margin, bool debug_save){ QMargins margins(margin, margin, margin, margin); bbox += margins; // Clamp to within image - note zero-indexed so boundary is width-1 etc. bbox.setTop(std::max(bbox.top(), 0)); bbox.setBottom(std::min(bbox.bottom(),image.rows-1)); bbox.setLeft(std::max(bbox.left(), 0)); bbox.setRight(std::min(bbox.right(), image.cols-1)); auto roi = image(qrect2cv(bbox)); // First we need to do foreground/background segmentation // Threshold input, 1 == good cv::Mat roi_thresh; // Convert colour images to grayscale for thresholding if(roi.channels() == 4){ cv::cvtColor(roi, roi, cv::COLOR_BGRA2GRAY); } else if(roi.channels() == 3){ cv::cvtColor(roi, roi, cv::COLOR_BGR2GRAY); } cv::threshold(roi, roi_thresh, 0, 255, cv::THRESH_OTSU|cv::THRESH_BINARY); if(debug_save) cv::imwrite("roi.png", roi); if(debug_save) cv::imwrite("roi_thresh.png", roi_thresh); std::vector> contours; cv::Mat hierarchy; cv::findContours(roi_thresh, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); for(auto &contour : contours){ if(static_cast(cv::contourArea(contour)) == roi.rows*roi.cols){ qDebug() << "Contour encloses all!"; } //cv::drawContours(markers, {contour}, 0, {0,0,255}); auto contour_bound = cv::boundingRect(contour); cv::rectangle(roi, contour_bound, {0,0,255}); } if(debug_save) cv::imwrite("roi_contours.png", roi); QRect new_box; if(contours.size() > 0){ auto contour_bound = cv::boundingRect(contours.at(0)); new_box.setX(bbox.x()+contour_bound.x); new_box.setY(bbox.y()+contour_bound.y); new_box.setWidth(contour_bound.width); new_box.setHeight(contour_bound.height); } return new_box; } QRect MainWindow::refineBoundingBox(cv::Mat image, QRect bbox, int margin, bool debug_save){ // Simple connected components refinement - debug only for now. QMargins margins(margin, margin, margin, margin); bbox += margins; bbox.setTop(std::max(0, std::min(image.rows, bbox.top()))); bbox.setBottom(std::max(0, std::min(image.rows, bbox.top()))); bbox.setLeft(std::max(0, std::min(image.cols, bbox.left()))); bbox.setRight(std::max(0, std::min(image.cols, bbox.right()))); auto roi = image(qrect2cv(bbox)); // First we need to do foreground/background segmentation // Threshold input, 1 == good cv::Mat roi_thresh; cv::threshold(roi, roi_thresh, 0, 255, cv::THRESH_OTSU|cv::THRESH_BINARY); if(debug_save) cv::imwrite("roi.png", roi); if(debug_save) cv::imwrite("roi_thresh.png", roi_thresh); auto kernel_size = cv::Size(3,3); int iterations = 2; auto anchor = cv::Point(-1,-1); auto structure = cv::getStructuringElement(cv::MORPH_RECT, kernel_size); cv::Mat opening; cv::morphologyEx(roi_thresh, opening, cv::MORPH_OPEN, structure, anchor, iterations); // Background area iterations = 3; cv::Mat background; cv::dilate(opening, background, structure, anchor, iterations); if(debug_save) cv::imwrite("background.png", background); // Foreground area cv::Mat dist_transform; cv::Mat dist_labels; int mask_size = 5; cv::distanceTransform(opening, dist_transform, dist_labels, cv::DIST_L2, mask_size); if(debug_save) cv::imwrite("distance.png", dist_transform); cv::Mat foreground; double min_val, max_val; cv::minMaxIdx(dist_transform, &min_val, &max_val); int thresh = static_cast(0.7*max_val); cv::threshold(dist_transform, foreground, thresh, 255, cv::THRESH_BINARY); foreground.convertTo(foreground, CV_8UC1); if(debug_save) cv::imwrite("foreground.png", foreground); // Unknown region cv::Mat unknown; cv::subtract(background, foreground, unknown, cv::noArray(), CV_8UC1); if(debug_save) cv::imwrite("unknown.png", unknown); cv::Mat markers; cv::connectedComponents(foreground, markers, 8, CV_32SC1); markers += 1; int region_id = markers.at(cv::Point(markers.cols/2, markers.rows/2)); qDebug() << region_id; for(int i=0; i < static_cast(markers.total()); i++){ if(unknown.at(i) == 255){ markers.at(i) = 0; } } if(debug_save) cv::imwrite("markers.png", markers); if(roi.channels() == 1) cv::cvtColor(roi, roi, cv::COLOR_GRAY2BGR); cv::watershed(roi, markers); markers.convertTo(markers, CV_8UC1); cv::threshold(markers, markers, 0, 255, cv::THRESH_OTSU); if(debug_save) cv::imwrite("watershed.png", markers); std::vector> contours; cv::Mat hierarchy; cv::findContours(markers, contours, hierarchy, cv::RETR_CCOMP, cv::CHAIN_APPROX_SIMPLE); cv::cvtColor(markers, markers, cv::COLOR_GRAY2BGR); cv::Rect contour_bound; for(auto &contour : contours){ if(static_cast(cv::contourArea(contour)) == roi.rows*roi.cols){ qDebug() << "Contour encloses all!"; } //cv::drawContours(markers, {contour}, 0, {0,0,255}); contour_bound = cv::boundingRect(contour); cv::rectangle(markers, contour_bound, {0,0,255}); } if(debug_save) cv::imwrite("contours.png", markers); QRect new_box; if(contours.size() == 1){ new_box.setX(bbox.x()+contour_bound.x); new_box.setY(bbox.y()+contour_bound.y); new_box.setWidth(contour_bound.width); new_box.setHeight(contour_bound.height); } return new_box; } void MainWindow::refineBoxes(double min_new_area, double max_new_area){ auto bboxes = currentImage->getBoundingBoxes(); const auto image = currentImage->getImage(); for(auto &bbox : bboxes){ auto previous_area = bbox.rect.width()*bbox.rect.height(); auto updated = refineBoundingBoxSimple(image, bbox.rect, 5, false); auto new_bbox = bbox; new_bbox.rect = updated; auto new_area = new_bbox.rect.width()*new_bbox.rect.height(); // Make sure that new bbox isn't changed // too much if(!updated.size().isEmpty() && new_area >= min_new_area*previous_area && new_area <= max_new_area*previous_area){ updateLabel(bbox, new_bbox); } } updateLabels(); } void MainWindow::initTrackers(void){ multitracker->init(currentImage->getImage(), currentImage->getBoundingBoxes()); } void MainWindow::updateTrackers(void){ // If there are no labels, and we're tracking the previous frame // propagate the bounding boxes. Otherwise we assume that the // current labels are the correct ones and should override. auto image = currentImage->getImage(); if(image.empty()) return; multitracker->update(image); auto new_bboxes = multitracker->getBoxes(); for(auto &new_bbox : new_bboxes){ project->addLabel(current_imagepath, new_bbox); } updateLabels(); } void MainWindow::nextImage(){ if(images.empty()) return; if(current_index == (number_images-1)){ if(wrap_index){ current_index = 0; }else{ return; } }else{ current_index++; } ui->imageNumberSpinbox->setValue(current_index+1); // Show the new image updateDisplay(); // Only auto-propagtae if we've enabled it and there are no boxes in the image already. if(track_previous && currentImage->getBoundingBoxes().size() == 0){ updateTrackers(); if(refine_on_propagate){ refineBoxes(); } } updateLabels(); } void MainWindow::previousImage(){ if(images.empty()) return; if(current_index == 0){ if(wrap_index){ current_index = number_images - 1; }else{ return; } }else{ current_index--; } ui->imageNumberSpinbox->setValue(current_index+1); updateDisplay(); } void MainWindow::updateCurrentIndex(int index){ current_index = index; ui->imageNumberSpinbox->setValue(current_index); updateDisplay(); } void MainWindow::updateDisplay(){ if(images.size() == 0){ return; }else{ current_index = ui->imageNumberSpinbox->value()-1; current_imagepath = images.at(current_index); display->setImagePath(current_imagepath); ui->statusBar->showMessage(current_imagepath); updateLabels(); ui->imageProgressBar->setValue(current_index+1); ui->imageIndexLabel->setText(QString("%1/%2").arg(current_index+1).arg(number_images)); } } void MainWindow::updateImageInfo(void){ auto image_info = QFileInfo(current_imagepath); ui->imageBitDepthLabel->setText(QString("%1 bit").arg(display->getBitDepth())); ui->filenameLabel->setText(image_info.fileName()); ui->filenameLabel->setToolTip(image_info.fileName()); ui->filetypeLabel->setText(image_info.completeSuffix()); ui->sizeLabel->setText(QString("%1 kB").arg(image_info.size() / 1000)); ui->dimensionsLabel->setText(QString("(%1, %2) px").arg(currentImage->getImage().cols).arg(currentImage->getImage().rows)); } void MainWindow::newProject() { QString openDir = settings->value("project_folder", QDir::homePath()).toString(); QFileDialog dialog(this); dialog.setDefaultSuffix(".lbldb"); QString fileName = dialog.getSaveFileName(this, tr("New Project"), openDir, tr("Label database (*.lbldb)")); if(fileName != ""){ free(project); project = new LabelProject; project->createDatabase(fileName); openProject(fileName); } return; } void MainWindow::addVideo(void){ QString openDir = QDir::homePath(); QString video_filename = QFileDialog::getOpenFileName(this, tr("Select video"), openDir); QString output_folder = QFileDialog::getExistingDirectory(this, "Output folder", openDir); if(video_filename != ""){ auto dialog_box = new QDialog(this); auto frame_skip_spin = new QSpinBox; auto frame_skip_label = new QLabel; auto layout = new QVBoxLayout; auto accept_button = new QPushButton; accept_button->setDefault(true); accept_button->setText("OK"); connect(accept_button, SIGNAL(clicked()), dialog_box, SLOT(accept())); frame_skip_spin->setValue(1); frame_skip_spin->setMinimum(1); frame_skip_spin->setMaximum(1000); frame_skip_label->setText("Skip frames (1 to use all): "); dialog_box->setWindowModality(Qt::WindowModal); dialog_box->setLayout(layout); dialog_box->layout()->addWidget(frame_skip_label); dialog_box->layout()->addWidget(frame_skip_spin); dialog_box->layout()->addWidget(accept_button); if(dialog_box->exec()){ qInfo() << "Frame skip: " << frame_skip_spin->value(); project->addVideo(video_filename, output_folder, frame_skip_spin->value()); } } updateImageList(); initDisplay(); } void MainWindow::addImages(void){ QString openDir = settings->value("data_folder", QDir::homePath()).toString(); QStringList image_filenames = QFileDialog::getOpenFileNames(this, tr("Select image(s)"), openDir, tr("JPEG (*.jpg *.jpeg *.JPG *.JPEG);;PNG (*.png *.PNG);;BMP (*.bmp *.BMP);;TIFF (*.tif *.tiff *.TIF *.TIFF);;All images (*.jpg *.jpeg *.png *.bmp *.tiff)")); if(image_filenames.size() != 0){ QString path; QProgressDialog progress("Loading images", "Abort", 0, image_filenames.size(), this); progress.setWindowModality(Qt::WindowModal); int i=0; foreach(path, image_filenames){ if(progress.wasCanceled()){ break; } project->addAsset(path); progress.setValue(i++); } settings->setValue("data_folder", QDir(image_filenames.at(0)).dirName()); } updateImageList(); initDisplay(); return; } void MainWindow::addImageFolder(void){ QString openDir = settings->value("data_folder", QDir::homePath()).toString(); QString path = QFileDialog::getExistingDirectory(this, tr("Select image folder"), openDir); if(path != ""){ int number_added = project->addImageFolder(path); settings->setValue("data_folder", path); qInfo() << "Added: " << number_added << " images"; } updateImageList(); initDisplay(); return; } void MainWindow::handleExportDialog(){ // If we hit OK and not cancel if(export_dialog->result() != QDialog::Accepted ) return; QThread* export_thread = new QThread; BaseExporter* exporter = nullptr; if(export_dialog->getExporter() == "Kitti"){ exporter = new KittiExporter(project); }else if(export_dialog->getExporter() == "Darknet"){ exporter = new DarknetExporter(project); static_cast(exporter)->generateLabelIds(export_dialog->getNamesFile()); }else if(export_dialog->getExporter() == "Pascal VOC"){ exporter = new PascalVocExporter(project); static_cast(exporter)->setExportMap(export_dialog->getCreateLabelMap()); exporter->process(); }else if(export_dialog->getExporter().startsWith("COCO")){ exporter = new CocoExporter(project); }else if(export_dialog->getExporter().startsWith("GCP")){ exporter = new GCPExporter(project); static_cast(exporter)->setBucket(export_dialog->getBucket()); }else{ qCritical() << "Invalid exporter type"; return; } if(exporter != nullptr){ exporter->moveToThread(export_thread); exporter->setExportUnlabelled(export_dialog->getExportUnlablled()); exporter->setFilenamePrefix(export_dialog->getFilePrefix()); exporter->setAppendLabels(export_dialog->getAppendLabels()); if(export_dialog->getValidationSplitEnabled()){ exporter->setValidationSplit(true); exporter->splitData(export_dialog->getValidationSplit(), export_dialog->getShuffle()); }else{ exporter->setValidationSplit(false); exporter->splitData(0, export_dialog->getShuffle()); } exporter->setOutputFolder(export_dialog->getOutputFolder()); exporter->process(); }else{ qCritical() << "Failed to instantiate exporter"; } } void MainWindow::launchExportDialog(){ export_dialog = new ExportDialog(this); export_dialog->setModal(true); connect(export_dialog, SIGNAL(accepted()), this, SLOT(handleExportDialog())); export_dialog->open(); } void MainWindow::handleRefineRange(){ if(refine_range_dialog->result() != QDialog::Accepted ){ return; } refineRange(refine_range_dialog->getStart(), refine_range_dialog->getEnd()); } void MainWindow::refineRange(int start, int end){ if(start == -1 || end == -1) return; QList images; project->getImageList(images); QProgressDialog progress("Refining images", "Cancel", 0, end-start, this); progress.setWindowModality(Qt::WindowModal); progress.setLabelText("..."); QApplication::processEvents(); // Otherwise stuff can happen a wee bit fast for(int i = start; i < end; ++i){ if(progress.wasCanceled()) break; progress.setLabelText(images[i]); updateCurrentIndex(i); refineBoxes(); nextImage(); progress.setValue(i); QApplication::processEvents(); } } void MainWindow::computeStatistics(void){ QList images; project->getImageList(images); std::vector histograms; histograms.resize(4); QProgressDialog progress("...", "Abort", 0, images.size(), this->parentWidget()); progress.setWindowModality(Qt::WindowModal); progress.setWindowTitle("Calculating stats"); progress.show(); int i = 0; for(auto &image_path : images){ if(progress.wasCanceled()) break; auto image = cv::imread(image_path.toStdString(), cv::IMREAD_UNCHANGED); std::vector image_channels; cv::split( image, image_channels ); int histSize = 65536; float range[] = { 0, 65536 }; //the upper boundary is exclusive const float* histRange = { range }; bool uniform = true, accumulate = true; for(int c=0; c < static_cast(image_channels.size()); ++c){ cv::calcHist( &image_channels[c], 1, 0, cv::Mat(), histograms[c], 1, &histSize, &histRange, uniform, accumulate ); } progress.setValue(++i); progress.setLabelText(image_path); QApplication::processEvents(); } for(auto &histogram : histograms){ double s = 0; double total_hist = 0; for(long long i=0; i < static_cast(histogram.total()); ++i){ s += histogram.at(i) * (i + 0.5); // bin centre total_hist += histogram.at(i); } double mean = s / total_hist; double t = 0; for(long long i=0; i < static_cast(histogram.total()); ++i){ double x = (i - mean); t += histogram.at(i)*x*x; } double stdev = std::sqrt(t / total_hist); qInfo() << "Mean: " << mean; qInfo() << "Std: " << stdev; } } void MainWindow::handleImportDialog(){ // If we hit OK and not cancel if (import_dialog->result() != QDialog::Accepted) return; QThread* import_thread = new QThread; if (import_dialog->getImporter() == "Darknet") { DarknetImporter importer(project); importer.moveToThread(import_thread); importer.setImportUnlabelled(import_dialog->getImportUnlabelled()); if (import_dialog->getUseRelativePaths()) { importer.import(import_dialog->getInputFile(), import_dialog->getNamesFile(), import_dialog->getRelativePath()); } else { importer.import(import_dialog->getInputFile(), import_dialog->getNamesFile()); } } else if (import_dialog->getImporter() == "Coco") { CocoImporter importer(project); importer.moveToThread(import_thread); importer.setImportUnlabelled(import_dialog->getImportUnlabelled()); importer.import(import_dialog->getAnnotationFile(), import_dialog->getInputFile()); } else if (import_dialog->getImporter() == "MOT") { MOTImporter importer(project); importer.moveToThread(import_thread); importer.setImportUnlabelled(import_dialog->getImportUnlabelled()); importer.loadClasses(import_dialog->getNamesFile()); importer.import(import_dialog->getInputFile()); } else if (import_dialog->getImporter() == "BirdsAI") { BirdsAIImporter importer(project); importer.moveToThread(import_thread); importer.setImportUnlabelled(import_dialog->getImportUnlabelled()); importer.loadClasses(import_dialog->getNamesFile()); importer.import(import_dialog->getInputFile(), import_dialog->getAnnotationFile()); } else if (import_dialog->getImporter() == "PascalVOC") { PascalVOCImporter importer(project); importer.moveToThread(import_thread); importer.setImportUnlabelled(import_dialog->getImportUnlabelled()); importer.import(import_dialog->getInputFile(), import_dialog->getAnnotationFile()); } initDisplay(); } void MainWindow::launchImportDialog(){ import_dialog = new ImportDialog(this); import_dialog->setModal(true); connect(import_dialog, SIGNAL(accepted()), this, SLOT(handleImportDialog())); import_dialog->open(); } MainWindow::~MainWindow() { delete ui; } ================================================ FILE: src/mainwindow.h ================================================ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = nullptr); ~MainWindow(); private: Ui::MainWindow *ui; LabelProject *project; ImageLabel *currentImage; ExportDialog *export_dialog; ImportDialog *import_dialog; RefineRangeDialog *refine_range_dialog; MultiTracker *multitracker; QScrollArea *imageScrollArea; ImageDisplay *display; DetectorOpenCV detector; // Enable tracking boxes in previous frames bool track_previous = false; bool refine_on_propagate = false; bool wrap_index; int current_index; void initDisplay(); QList images; QList classes; QString current_imagepath; QString current_class; int number_images; void updateImageList(); void updateClassList(); void updateLabels(); QSettings* settings; private slots: void updateDisplay(void); void openProject(QString filename = ""); void mergeProject(QString filename = ""); void newProject(void); void addClass(void); void setCurrentClass(QString); void removeClass(void); void addVideo(void); void addImages(void); void addImageFolder(void); void addImageFolders(); void nextImage(void); void previousImage(void); void removeImage(void); void addLabel(BoundingBox bbox); void removeLabel(BoundingBox bbox); void updateLabel(BoundingBox old_bbox, BoundingBox new_bbox); void removeImageLabels(void); void removeImageLabelsForward(); void setDrawMode(void); void setSelectMode(void); void enableWrap(bool enable); void launchExportDialog(); void handleExportDialog(); void launchImportDialog(); void handleImportDialog(); // Tracking void initTrackers(); void updateTrackers(); void toggleAutoPropagate(bool state); void toggleRefineTracking(bool state); void nextUnlabelled(); void nextInstance(); QRect refineBoundingBox(cv::Mat image, QRect bbox, int margin=5, bool debug_save=false); QRect refineBoundingBoxSimple(cv::Mat image, QRect bbox, int margin=5, bool debug_save=false); void refineBoxes(double min_new_area = 0.5, double max_new_area = 1.5); void updateImageInfo(); void jumpForward(int n = 10); void jumpBackward(int n = 10); void detectObjects(cv::Mat &image, QString image_path); void detectCurrentImage(); void detectProject(); void setupDetector(); void setConfidenceThreshold(); void setNMSThreshold(); void computeStatistics(); void updateCurrentIndex(int index); void refineRange(int start, int end); void handleRefineRange(); signals: void selectedClass(QString); }; #endif // MAINWINDOW_H ================================================ FILE: src/mainwindow.ui ================================================ MainWindow 0 0 931 698 DeepLabel QLayout::SetDefaultConstraint QLayout::SetDefaultConstraint false 350 16777215 Navigation Image: 0/0 Track labels Jump to image Refine after tracking 300 16777215 1 0 0 300 16777215 0 false false Image %v/%m Next Unlabelled false 300 0 300 16777215 Labelling Next instance Current label class Remove class New class name Add class Remove image labels false 300 0 300 16777215 Image Attributes Filetype: Filename: - - Dimensions: - Instances labelled: - Size on disk: Bit Depth 0 Remove image Inferno Bone Viridis Plasma Magma Hot Rainbow Ocean Cividis Colour Map Apply colour map true Qt::Vertical 20 40 0 0 931 21 File false Navigation false Detection false Images false Labeling false false false TopToolBarArea false false Prev Previous Image A Next D New Project Ctrl+N Open Project Ctrl+O true Add image(s) true Add image folder Add class Draw Create rectangular labels Shift+D Select Select labels for viewing/deletion Shift+S true Two-click true Drag true Wrap images Init Tracking Initialise object tracker with this image Ctrl+I Propagate Tracking Ctrl+P false Export labels Refine boxes Ctrl+R Add video(s) Add image folders Jump forward Ctrl+Right Jump backward Ctrl+Left Next Image Previous Image true Setup detector Detect Objects Set confidence threshold false Run on project Set NMS threshold false Merge Project false Import Labels calculateHistograms true Calculate histograms Refine image range Remove labels forwards Remove image labels classComboBox ================================================ FILE: src/motimporter.cpp ================================================ #include "motimporter.h" void MOTImporter::importSequence(QString folder){ auto ini_filename = QDir(folder).absoluteFilePath("seqinfo.ini"); auto sequence_name = QFileInfo(folder).baseName(); // Load image folder path from ini file QSettings seq_ini(ini_filename, QSettings::IniFormat); seq_ini.setIniCodec(QTextCodec::codecForName("UTF-8")); seq_ini.beginGroup("Sequence"); if(!seq_ini.contains("imDir")){ qCritical() << ini_filename << " doesn't contain image directory"; return; } auto image_foldername = seq_ini.value("imDir").toString(); if(image_foldername == ""){ qCritical() << "Image folder value in INI file is empty"; return; } qDebug() << "Image folder:" << image_foldername; auto image_folder = QDir(folder).absoluteFilePath(image_foldername); qDebug() << "Adding images from " << image_folder; QList> label_list; QList image_list; // Find and load gt.txt file: auto annotation_dir = QDir(QDir(folder).absoluteFilePath("gt")); QString annotation_file = annotation_dir .absoluteFilePath(QString("gt.txt")); qDebug() << "Looking for: " << annotation_file; // Find images: qInfo() << "Loading annotations"; auto labels = getLabels(annotation_file); qInfo() << "Checking images"; auto pbar = cliProgressBar(); double progress = 0; int i = 0; auto images = QDir(image_folder).entryList(QDir::Files); for(auto & image : images){ qDebug() << "Adding labels for" << image; // Extract image ID, ignoring leading zeros auto split_file = QFileInfo(image).baseName().split("_"); int image_id = split_file.back().toInt(); // Get boxes for this ID and add to DB auto boxes = findBoxes(labels, image_id); progress = 100*static_cast(i++)/images.size(); pbar.update(progress); pbar.print(); QString abs_image_path = QDir(image_folder).absoluteFilePath(image); if(boxes.empty() && !import_unlabelled){ continue; } label_list.append(boxes); image_list.append(abs_image_path); } qInfo() << "\nInserting into database"; project->addLabelledAssets(image_list, label_list); } void MOTImporter::import(QString sequence_folder){ QDir seq_dir(sequence_folder); // Find all sequence folders QDirIterator it(sequence_folder, QDir::Dirs | QDir::NoDotAndDotDot); QList subfolders; while (it.hasNext()) { auto subfolder = QDir(it.next()).canonicalPath(); subfolders.append(subfolder); } if(subfolders.size() == 0){ qWarning() << "Couldn't find any sequences in " << sequence_folder; return; } subfolders.removeDuplicates(); subfolders.sort(); for(auto &subfolder : subfolders){ qInfo() << "Processing: " << subfolder; importSequence(subfolder); } } QVector MOTImporter::getLabels(QString annotation_file){ auto lines = readLines(annotation_file); QVector labels; auto pbar = cliProgressBar(); double progress = 0; int i = 0; for(auto &line : lines){ auto label = line.simplified().split(","); // Note - MOT docs say 10, but MOTDet only contains 9 elements if(label.size() < 8){ qWarning() << "Found :" << label.size() << " elements - need at least 9."; continue; }else{ labels.push_back(label); } progress = 100*static_cast(i++)/lines.size(); pbar.update(progress); pbar.print(); } qInfo() << ""; return labels; } QList MOTImporter::findBoxes(QVector labels, int id){ QList boxes = {}; // , , , , , , , , , for(auto &label : labels){ if(label.at(0).toInt() != id){ continue; } BoundingBox bbox; bbox.classid = label.at(7).toInt(); bbox.classname = project->getClassName(bbox.classid); if(bbox.classname == ""){ qWarning() << "Class" << bbox.classid << " not found in names file."; } auto top_left = QPoint(label.at(2).toDouble(), label.at(3).toDouble()); auto bottom_right = top_left + QPoint(label.at(4).toDouble(), label.at(5).toDouble()); bbox.rect = QRect(top_left, bottom_right); boxes.append(bbox); } return boxes; } void MOTImporter::loadClasses(QString names_file){ QFile fh(names_file); QList class_list; project->getClassList(class_list); if (fh.open(QIODevice::ReadOnly)) { while (!fh.atEnd()) { // Darknet name file is just a newline delimited list of classes QByteArray line = fh.readLine(); if(QString(line) == "") continue; auto new_class = line.simplified(); if(!class_list.contains(new_class)){ project->addClass(new_class); }else{ qDebug() << "Added: " << new_class; } } } } ================================================ FILE: src/motimporter.h ================================================ #ifndef MOTIMPORTER_H #define MOTIMPORTER_H #include "baseimporter.h" #include #include class MOTImporter : public BaseImporter { public: using BaseImporter::import; explicit MOTImporter(LabelProject *project, QObject *parent = nullptr) : BaseImporter(parent){ this->project = project; } void import(QString sequence_folder); void importSequence(QString folder); void loadClasses(QString names_file); protected: QVector getLabels(QString annotation_file); virtual QList findBoxes(QVector labels, int id); QString findImage(QList *images, QString sequence_name, int image_id); }; #endif // MOTIMPORTER_H ================================================ FILE: src/multitracker.cpp ================================================ #include "multitracker.h" cv::Rect2d qrect2cv(QRect rect){ return cv::Rect2d(rect.x(), rect.y(), rect.width(),rect.height()); } /* ---- OpenCV Trackers ---- */ cv::Ptr MultiTrackerCV::createTrackerByName(OpenCVTrackerType type){ using namespace cv; Ptr tracker; if (type == MIL) tracker = TrackerMIL::create(); else if (type == KCF) tracker = TrackerKCF::create(); else if (type == GOTURN) tracker = TrackerGOTURN::create(); else if (type == CSRT) tracker = TrackerCSRT::create(); else { qCritical() << "Incorrect tracker specified"; } tracker = TrackerCSRT::create(); return tracker; } void MultiTrackerCV::init(const cv::Mat &image, QList bboxes){ trackers.clear(); QMutex mutex; // If we are tracking and we have some labelled boxes already QtConcurrent::blockingMap(bboxes.begin(), bboxes.end(), [&](BoundingBox &bbox) { if(bbox.rect.width()*bbox.rect.height() <= 0) return; auto tracker = createTrackerByName(type_); tracker->init(image, qrect2cv(bbox.rect)); mutex.lock(); trackers.push_back({tracker, bbox.classname}); mutex.unlock(); }); } void MultiTrackerCV::update(const cv::Mat &image){ QMutex mutex; bboxes.clear(); QtConcurrent::blockingMap(trackers.begin(), trackers.end(), [&](auto&& tracker) { cv::Rect bbox; if( tracker.first->update(image, bbox)){ QRect new_roi; new_roi.setX(static_cast(bbox.x)); new_roi.setY(static_cast(bbox.y)); new_roi.setWidth(static_cast(bbox.width)); new_roi.setHeight(static_cast(bbox.height)); BoundingBox new_bbox; new_bbox.rect = new_roi; new_bbox.classname = tracker.second; mutex.lock(); bboxes.append(new_bbox); mutex.unlock(); } }); } /* ---- CamShift Tracker ---- */ void MultiTrackerCamshift::init(const cv::Mat &image, QList bboxes){ trackers.clear(); QMutex mutex; QtConcurrent::blockingMap(bboxes.begin(), bboxes.end(), [&](BoundingBox &bbox) { auto roi_hist = getRoiHist(image, bbox.rect); mutex.lock(); trackers.push_back({roi_hist, bbox}); mutex.unlock(); }); } void MultiTrackerCamshift::update(const cv::Mat &image){ QMutex mutex; bboxes.clear(); QtConcurrent::blockingMap(trackers.begin(), trackers.end(), [&](auto&& tracker) { // image, roi_hist, bbox cv::Rect2i bbox = this->updateCamshift(image, tracker.first, tracker.second.rect); QRect new_roi; new_roi.setX(static_cast(bbox.x)); new_roi.setY(static_cast(bbox.y)); new_roi.setWidth(static_cast(bbox.width)); new_roi.setHeight(static_cast(bbox.height)); BoundingBox new_bbox; new_bbox.rect = new_roi; new_bbox.classname = tracker.second.classname; mutex.lock(); bboxes.append(new_bbox); mutex.unlock(); }); } cv::Mat MultiTrackerCamshift::getRoiHist(const cv::Mat &image, QRect bbox){ auto roi = image(qrect2cv(bbox)); cv::Mat mask; if(roi.channels() == 1){ //cv::cvtColor(roi, roi, cv::COLOR_GRAY2BGR); //cv::cvtColor(roi, roi, cv::COLOR_BGR2HSV); auto lowScalar = cv::Scalar(30); auto highScalar = cv::Scalar(180); cv::inRange(roi, lowScalar, highScalar, mask); }else if(roi.channels() == 3){ cv::cvtColor(roi, roi, cv::COLOR_BGR2HSV); auto lowScalar = cv::Scalar(30,30,30); auto highScalar = cv::Scalar(180,180,180); cv::inRange(roi, lowScalar, highScalar, mask); }else{ // What the hell kind of 2 channel image is this? return cv::Mat(); } // Generate histogram cv::Mat roiHist; int histSize = 256; float range[] = { 0, 180 }; //the upper boundary is exclusive const float* histRange = { range }; bool uniform = true; bool accumulate = true; int n_images = 1; int *use_channels = nullptr; int n_dims = 1; cv::calcHist( &roi, n_images, use_channels, mask, roiHist, n_dims, &histSize, &histRange, uniform, accumulate); cv::normalize(roiHist, roiHist, 0, 255, cv::NORM_MINMAX); return roiHist; } cv::Rect2i MultiTrackerCamshift::updateCamshift(const cv::Mat &image, cv::Mat roiHist, QRect bbox){ auto rect = qrect2cv(bbox); auto roi = image(rect); if(roi.channels() == 1){ //cv::cvtColor(roi, roi, cv::COLOR_GRAY2BGR); cv::cvtColor(roi, roi, cv::COLOR_BGR2HSV); }else if(roi.channels() == 3){ cv::cvtColor(roi, roi, cv::COLOR_BGR2HSV); }else{ // What the hell kind of 2 channel image is this? return cv::Rect(); } auto rectInt = cv::Rect2i(rect); cv::Mat backProjection; float range[] = { 0, 180 }; //the upper boundary is exclusive const float* histRange = { range }; cv::calcBackProject(&image, 1, nullptr, roiHist, backProjection, &histRange); auto termcrit = cv::TermCriteria(cv::TermCriteria::EPS|cv::TermCriteria::COUNT, 10, 1); auto rotated_rect = cv::CamShift(backProjection, rectInt, termcrit); return rotated_rect.boundingRect(); } void MultiTrackerCamshift::histogram(const cv::Mat &image, cv::Mat &hist){ int histSize = 256; float range[] = { 0, 256 }; //the upper boundary is exclusive const float* histRange = { range }; bool uniform = true; bool accumulate = true; calcHist( &image, 1, nullptr, cv::Mat(), hist, 1, &histSize, &histRange, uniform, accumulate); } ================================================ FILE: src/multitracker.h ================================================ #ifndef TRACKER_H #define TRACKER_H #include #include #include #include #include enum OpenCVTrackerType {BOOSTING, MIL, KCF, TLD, MEDIANFLOW, GOTURN, MOSSE, CSRT}; enum MultiTrackerType {OPENCV, CAMSHIFT}; cv::Rect2d qrect2cv(QRect rect); class MultiTracker : public QObject { Q_OBJECT public: explicit MultiTracker(QObject *parent = nullptr) : QObject(parent){} signals: public slots: QList getBoxes(){ return bboxes;} virtual void init(const cv::Mat &image, QList bboxes) = 0; virtual void update(const cv::Mat &image) = 0; protected: QList bboxes; }; class MultiTrackerCV : public MultiTracker { Q_OBJECT public: explicit MultiTrackerCV(QObject *parent = nullptr) : MultiTracker(parent){} public slots: void init(const cv::Mat &image, QList bboxes); void update(const cv::Mat &image); void setTrackerType(OpenCVTrackerType type){ type_ = type; } private: std::vector, QString>> trackers; cv::Ptr createTrackerByName(OpenCVTrackerType MultiTracker); OpenCVTrackerType type_; }; class MultiTrackerCamshift : public MultiTracker { Q_OBJECT public: explicit MultiTrackerCamshift(QObject *parent = nullptr) : MultiTracker(parent){} void init(const cv::Mat &image, QList bboxes); void update(const cv::Mat &image); private: std::vector> trackers; cv::Rect2i updateCamshift(const cv::Mat &image, cv::Mat roiHist, QRect bbox); cv::Mat getRoiHist(const cv::Mat &image, QRect bbox); void histogram(const cv::Mat &image, cv::Mat &hist); }; #endif // TRACKER_H ================================================ FILE: src/pascalvocexporter.cpp ================================================ #include "pascalvocexporter.h" void PascalVocExporter::splitData(float split, bool shuffle, int seed){ if(split < 0 || split > 1){ qCritical() << "Invalid split fraction, should be [0,1]"; } if(shuffle){ std::random_device rd; std::mt19937 generator(rd()); generator.seed(static_cast(seed)); std::shuffle(images.begin(), images.end(), generator); } int pivot = static_cast(images.size() * split); train_set = images.mid(0, pivot); validation_set = images.mid(pivot); qInfo() << train_set.size() << " images selected for train set."; qInfo() << validation_set.size() << " images selected for validation set."; } bool PascalVocExporter::setOutputFolder(const QString folder){ if(folder == "") return false; output_folder = folder; //Make output folder if it doesn't exist if (!QDir(output_folder).exists()){ qInfo() << "Making output folder" << output_folder; QDir().mkpath(output_folder); } //Make the training and validation folders train_folder = QDir::cleanPath(output_folder+"/train"); if (!QDir(train_folder).exists()){ qInfo() << "Making training folder" << train_folder; QDir().mkpath(train_folder); } val_folder = QDir::cleanPath(output_folder+"/val"); if (!QDir(val_folder).exists()){ qInfo() << "Making validation folder" << val_folder; QDir().mkpath(val_folder); } train_label_folder = QDir::cleanPath(train_folder); train_image_folder = QDir::cleanPath(train_folder); val_label_folder = QDir::cleanPath(val_folder); val_image_folder = QDir::cleanPath(val_folder); return true; } void PascalVocExporter::writeLabels(const cv::Mat &image, const QString image_filename, const QString label_filename, const QList labels){ // Still make a label file even if there are no detections. This is important // for background class detection. QFile f(label_filename); // Delete existing files for simplicity. if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) { QXmlStreamWriter stream(&f); stream.setAutoFormatting(true); stream.writeStartDocument(); stream.writeStartElement("annotation"); auto finfo = QFileInfo(image_filename); stream.writeTextElement("folder", finfo.dir().dirName()); stream.writeTextElement("filename", finfo.fileName()); stream.writeTextElement("path", finfo.filePath()); QString label_database = ""; stream.writeStartElement("source"); stream.writeTextElement("database", label_database); stream.writeEndElement(); // source // Image properties stream.writeStartElement("size"); stream.writeTextElement("width", QString::number(image.cols)); stream.writeTextElement("height", QString::number(image.rows)); stream.writeTextElement("depth", QString::number(image.channels())); stream.writeEndElement(); // size // Not a segmentation mask stream.writeTextElement("segmented", "0"); // Labels for(auto &label : labels){ stream.writeStartElement("object"); stream.writeTextElement("name", label.classname); stream.writeTextElement("pose", "Unspecified"); stream.writeTextElement("truncated", "0"); stream.writeTextElement("difficult", "0"); stream.writeStartElement("bndbox"); stream.writeTextElement("xmin", QString::number(label.rect.left())); stream.writeTextElement("xmax", QString::number(label.rect.right())); stream.writeTextElement("ymin", QString::number(label.rect.top())); stream.writeTextElement("ymax", QString::number(label.rect.bottom())); stream.writeEndElement(); //bndbox stream.writeEndElement(); //object } stream.writeEndElement(); // annotation stream.writeEndDocument(); f.close(); } } bool PascalVocExporter::saveImage(cv::Mat &image, const QString output, const double scale_x, const double scale_y){ if(image.rows == 0 || image.cols == 0){ qCritical() << "Empty image "; return false; } if(scale_x > 0 && scale_y > 0) cv::resize(image, image, cv::Size(), scale_x, scale_y); std::vector compression_params; // Png compression - maximum is super slow // TODO: add support to adjust this if(output.split(".").last().toLower() == "png"){ compression_params.push_back(cv::IMWRITE_PNG_COMPRESSION); compression_params.push_back(6); } return cv::imwrite(output.toStdString(), image, compression_params); } bool PascalVocExporter::processImages(const QString folder, const QList images){ QString image_path; QList labels; QProgressDialog progress("...", "Abort", 0, images.size(), static_cast(parent())); progress.setWindowModality(Qt::WindowModal); if(disable_progress){ progress.hide(); } int i = 0; foreach(image_path, images){ if(progress.wasCanceled()){ break; } project->getLabels(image_path, labels); if(!export_unlabelled && labels.size() == 0){ if(!disable_progress){ progress.setValue(i); progress.setLabelText(QString("%1 is unlabelled").arg(image_path)); progress.repaint(); QApplication::processEvents(); } continue; } QString abs_image_path = project->getDbFolder().absoluteFilePath(image_path); QString extension = QFileInfo(image_path).suffix(); QString filename_noext = QFileInfo(image_path).completeBaseName(); QString image_filename = QString("%1/%2%3.%4").arg(folder).arg(filename_prefix).arg(filename_noext).arg(extension); // Correct for duplicate file names in output int dupe_file = 1; while(QFile(image_filename).exists()){ image_filename = QString("%1/%2%3_%4.%5").arg(folder).arg(filename_prefix).arg(filename_noext).arg(dupe_file++).arg(extension); } cv::Mat image = cv::imread(abs_image_path.toStdString()); // Copy the image to the new folder //saveImage(image, image_filename); QFile::copy(abs_image_path, image_filename); QString label_filename = QString("%1/%2.xml").arg(folder).arg(filename_noext); writeLabels(image, image_filename, label_filename, labels); if(!disable_progress){ progress.setValue(i++); progress.setLabelText(image_filename); QApplication::processEvents(); } } return true; } void PascalVocExporter::saveLabelMap(QString filename){ QFile f(filename); // Delete existing files for simplicity. if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) { QList classes; project->getClassList(classes); for(auto classname : classes){ f.write("item {\n"); f.write(QString(" name: %1\n").arg(classname).toStdString().c_str()); f.write(QString(" id: %1\n").arg(project->getClassId(classname)).toStdString().c_str()); f.write(QString(" displayname: %1\n").arg(classname).toStdString().c_str()); f.write("}\n"); } f.close(); } } void PascalVocExporter::process(){ processImages(train_folder, train_set); processImages(val_folder, validation_set); if(export_map){ saveLabelMap(QString("%1/%2").arg(output_folder).arg("label_map.pbtxt")); } } ================================================ FILE: src/pascalvocexporter.h ================================================ #ifndef PASCALVOCEXPORTER_H #define PASCALVOCEXPORTER_H #include #include #include #include #include #include #include #include #include class PascalVocExporter : public BaseExporter { Q_OBJECT public: explicit PascalVocExporter(LabelProject *project, QObject *parent = nullptr) : BaseExporter(project, parent){} signals: void export_progress(int); public slots: void splitData(float split=1, bool shuffle=false, int seed=42); bool setOutputFolder(QString folder); void setExportUnlabelled(bool res){export_unlabelled = res;} void setExportMap(bool map){export_map = map;} void process(); private: LabelProject *project; QList train_set; QList validation_set; QList images; QString train_folder; QString train_label_folder; QString train_image_folder; QString val_folder; QString val_label_folder; QString val_image_folder; QString output_folder; bool export_unlabelled = false; bool export_map; std::map id_map; void writeLabels(const cv::Mat &image, const QString image_filename, const QString label_filename, const QList labels); bool processImages(const QString folder, const QList images); void saveLabelMap(QString filename); bool saveImage(cv::Mat &image, const QString output, const double scale_x = -1.0, const double scale_y = -1.0); }; #endif // PASCALVOCEXPORTER_H ================================================ FILE: src/pascalvocimporter.cpp ================================================ #include "pascalvocimporter.h" void PascalVOCImporter::import(QString image_folder, QString annotation_folder){ QDir image_dir(image_folder); QDir annotation_dir(annotation_folder); QList> label_list; QList image_list; auto annotations = QDir(annotation_folder).entryList(QDir::Files|QDir::NoDotAndDotDot); auto pbar = cliProgressBar(); double progress = 0; int i = 0; for(auto & annotation : annotations){ qDebug() << annotation; auto abs_annotation_path = annotation_dir.absoluteFilePath(annotation); QString image_filename; auto labels = getLabels(abs_annotation_path, image_filename); auto abs_image_path = image_dir.absoluteFilePath(image_filename); progress = 100*static_cast(i++)/annotations.size(); pbar.update(progress); pbar.print(); if(!QFileInfo(abs_image_path).exists()){ qWarning() << "Couldn't find image: " << abs_image_path; continue; } if(labels.empty() && !import_unlabelled){ continue; } image_list.append(abs_image_path); label_list.append(labels); } qInfo() << "Importing images and labels"; project->addLabelledAssets(image_list, label_list); } QList PascalVOCImporter::getLabels(QString annotation_file, QString &image_filename){ QFile f(annotation_file); QDomDocument doc; QList labels; QList classes; project->getClassList(classes); if (!f.open(QIODevice::ReadOnly)) return labels; if (!doc.setContent(&f)) { f.close(); return labels; } auto objects = doc.elementsByTagName("object"); image_filename = doc.elementsByTagName("filename").at(0).toElement().text(); for(int i=0; i < objects.size(); i++){ BoundingBox new_box; auto object = objects.at(i).toElement(); auto name_node = object.elementsByTagName("name").at(0).toElement().text(); new_box.classname = object.elementsByTagName("name").at(0).toElement().text(); if(!classes.contains(new_box.classname)){ project->addClass(new_box.classname); classes.clear(); project->getClassList(classes); } new_box.classid = project->getClassId(new_box.classname); auto xmin = object.elementsByTagName("xmin").at(0).toElement().text().toInt(); auto ymin = object.elementsByTagName("ymin").at(0).toElement().text().toInt(); auto xmax = object.elementsByTagName("xmax").at(0).toElement().text().toInt(); auto ymax = object.elementsByTagName("ymax").at(0).toElement().text().toInt(); new_box.rect = QRect(QPoint(xmin, ymin), QPoint(xmax, ymax)); labels.append(new_box); } return labels; } ================================================ FILE: src/pascalvocimporter.h ================================================ #ifndef PASCALVOCIMPORTER_H #define PASCALVOCIMPORTER_H #include "baseimporter.h" #include class PascalVOCImporter : public BaseImporter { public: using BaseImporter::import; explicit PascalVOCImporter(LabelProject *project, QObject *parent = nullptr) : BaseImporter(parent){ this->project = project; } void import(QString image_folder, QString annotation_folder); private: QList getLabels(QString annotation_file, QString &image_file); }; #endif // PASCALVOCIMPORTER_H ================================================ FILE: src/proto/example.pb.cc ================================================ // Generated by the protocol buffer compiler. DO NOT EDIT! // source: example.proto #include "example.pb.h" #include #include #include #include #include #include #include #include // @@protoc_insertion_point(includes) #include PROTOBUF_PRAGMA_INIT_SEG namespace tensorflow { constexpr Example::Example( ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) : features_(nullptr){} struct ExampleDefaultTypeInternal { constexpr ExampleDefaultTypeInternal() : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} ~ExampleDefaultTypeInternal() {} union { Example _instance; }; }; PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT ExampleDefaultTypeInternal _Example_default_instance_; constexpr SequenceExample::SequenceExample( ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) : context_(nullptr) , feature_lists_(nullptr){} struct SequenceExampleDefaultTypeInternal { constexpr SequenceExampleDefaultTypeInternal() : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} ~SequenceExampleDefaultTypeInternal() {} union { SequenceExample _instance; }; }; PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT SequenceExampleDefaultTypeInternal _SequenceExample_default_instance_; } // namespace tensorflow static ::PROTOBUF_NAMESPACE_ID::Metadata file_level_metadata_example_2eproto[2]; static constexpr ::PROTOBUF_NAMESPACE_ID::EnumDescriptor const** file_level_enum_descriptors_example_2eproto = nullptr; static constexpr ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor const** file_level_service_descriptors_example_2eproto = nullptr; const ::PROTOBUF_NAMESPACE_ID::uint32 TableStruct_example_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { ~0u, // no _has_bits_ PROTOBUF_FIELD_OFFSET(::tensorflow::Example, _internal_metadata_), ~0u, // no _extensions_ ~0u, // no _oneof_case_ ~0u, // no _weak_field_map_ PROTOBUF_FIELD_OFFSET(::tensorflow::Example, features_), ~0u, // no _has_bits_ PROTOBUF_FIELD_OFFSET(::tensorflow::SequenceExample, _internal_metadata_), ~0u, // no _extensions_ ~0u, // no _oneof_case_ ~0u, // no _weak_field_map_ PROTOBUF_FIELD_OFFSET(::tensorflow::SequenceExample, context_), PROTOBUF_FIELD_OFFSET(::tensorflow::SequenceExample, feature_lists_), }; static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { { 0, -1, sizeof(::tensorflow::Example)}, { 6, -1, sizeof(::tensorflow::SequenceExample)}, }; static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = { reinterpret_cast(&::tensorflow::_Example_default_instance_), reinterpret_cast(&::tensorflow::_SequenceExample_default_instance_), }; const char descriptor_table_protodef_example_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = "\n\rexample.proto\022\ntensorflow\032\rfeature.pro" "to\"1\n\007Example\022&\n\010features\030\001 \001(\0132\024.tensor" "flow.Features\"i\n\017SequenceExample\022%\n\007cont" "ext\030\001 \001(\0132\024.tensorflow.Features\022/\n\rfeatu" "re_lists\030\002 \001(\0132\030.tensorflow.FeatureLists" "B\201\001\n\026org.tensorflow.exampleB\rExampleProt" "osP\001ZSgithub.com/tensorflow/tensorflow/t" "ensorflow/go/core/example/example_protos" "_go_proto\370\001\001b\006proto3" ; static const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable*const descriptor_table_example_2eproto_deps[1] = { &::descriptor_table_feature_2eproto, }; static ::PROTOBUF_NAMESPACE_ID::internal::once_flag descriptor_table_example_2eproto_once; const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_example_2eproto = { false, false, 340, descriptor_table_protodef_example_2eproto, "example.proto", &descriptor_table_example_2eproto_once, descriptor_table_example_2eproto_deps, 1, 2, schemas, file_default_instances, TableStruct_example_2eproto::offsets, file_level_metadata_example_2eproto, file_level_enum_descriptors_example_2eproto, file_level_service_descriptors_example_2eproto, }; PROTOBUF_ATTRIBUTE_WEAK ::PROTOBUF_NAMESPACE_ID::Metadata descriptor_table_example_2eproto_metadata_getter(int index) { ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_example_2eproto); return descriptor_table_example_2eproto.file_level_metadata[index]; } // Force running AddDescriptors() at dynamic initialization time. PROTOBUF_ATTRIBUTE_INIT_PRIORITY static ::PROTOBUF_NAMESPACE_ID::internal::AddDescriptorsRunner dynamic_init_dummy_example_2eproto(&descriptor_table_example_2eproto); namespace tensorflow { // =================================================================== class Example::_Internal { public: static const ::tensorflow::Features& features(const Example* msg); }; const ::tensorflow::Features& Example::_Internal::features(const Example* msg) { return *msg->features_; } void Example::clear_features() { if (GetArena() == nullptr && features_ != nullptr) { delete features_; } features_ = nullptr; } Example::Example(::PROTOBUF_NAMESPACE_ID::Arena* arena) : ::PROTOBUF_NAMESPACE_ID::Message(arena) { SharedCtor(); RegisterArenaDtor(arena); // @@protoc_insertion_point(arena_constructor:tensorflow.Example) } Example::Example(const Example& from) : ::PROTOBUF_NAMESPACE_ID::Message() { _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); if (from._internal_has_features()) { features_ = new ::tensorflow::Features(*from.features_); } else { features_ = nullptr; } // @@protoc_insertion_point(copy_constructor:tensorflow.Example) } void Example::SharedCtor() { features_ = nullptr; } Example::~Example() { // @@protoc_insertion_point(destructor:tensorflow.Example) SharedDtor(); _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); } void Example::SharedDtor() { GOOGLE_DCHECK(GetArena() == nullptr); if (this != internal_default_instance()) delete features_; } void Example::ArenaDtor(void* object) { Example* _this = reinterpret_cast< Example* >(object); (void)_this; } void Example::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { } void Example::SetCachedSize(int size) const { _cached_size_.Set(size); } void Example::Clear() { // @@protoc_insertion_point(message_clear_start:tensorflow.Example) ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused (void) cached_has_bits; if (GetArena() == nullptr && features_ != nullptr) { delete features_; } features_ = nullptr; _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); } const char* Example::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure while (!ctx->Done(&ptr)) { ::PROTOBUF_NAMESPACE_ID::uint32 tag; ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); CHK_(ptr); switch (tag >> 3) { // .tensorflow.Features features = 1; case 1: if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 10)) { ptr = ctx->ParseMessage(_internal_mutable_features(), ptr); CHK_(ptr); } else goto handle_unusual; continue; default: { handle_unusual: if ((tag & 7) == 4 || tag == 0) { ctx->SetLastTag(tag); goto success; } ptr = UnknownFieldParse(tag, _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), ptr, ctx); CHK_(ptr != nullptr); continue; } } // switch } // while success: return ptr; failure: ptr = nullptr; goto success; #undef CHK_ } ::PROTOBUF_NAMESPACE_ID::uint8* Example::_InternalSerialize( ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { // @@protoc_insertion_point(serialize_to_array_start:tensorflow.Example) ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; (void) cached_has_bits; // .tensorflow.Features features = 1; if (this->has_features()) { target = stream->EnsureSpace(target); target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: InternalWriteMessage( 1, _Internal::features(this), target, stream); } if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); } // @@protoc_insertion_point(serialize_to_array_end:tensorflow.Example) return target; } size_t Example::ByteSizeLong() const { // @@protoc_insertion_point(message_byte_size_start:tensorflow.Example) size_t total_size = 0; ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused (void) cached_has_bits; // .tensorflow.Features features = 1; if (this->has_features()) { total_size += 1 + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( *features_); } if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize( _internal_metadata_, total_size, &_cached_size_); } int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size); SetCachedSize(cached_size); return total_size; } void Example::MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) { // @@protoc_insertion_point(generalized_merge_from_start:tensorflow.Example) GOOGLE_DCHECK_NE(&from, this); const Example* source = ::PROTOBUF_NAMESPACE_ID::DynamicCastToGenerated( &from); if (source == nullptr) { // @@protoc_insertion_point(generalized_merge_from_cast_fail:tensorflow.Example) ::PROTOBUF_NAMESPACE_ID::internal::ReflectionOps::Merge(from, this); } else { // @@protoc_insertion_point(generalized_merge_from_cast_success:tensorflow.Example) MergeFrom(*source); } } void Example::MergeFrom(const Example& from) { // @@protoc_insertion_point(class_specific_merge_from_start:tensorflow.Example) GOOGLE_DCHECK_NE(&from, this); _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; (void) cached_has_bits; if (from.has_features()) { _internal_mutable_features()->::tensorflow::Features::MergeFrom(from._internal_features()); } } void Example::CopyFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) { // @@protoc_insertion_point(generalized_copy_from_start:tensorflow.Example) if (&from == this) return; Clear(); MergeFrom(from); } void Example::CopyFrom(const Example& from) { // @@protoc_insertion_point(class_specific_copy_from_start:tensorflow.Example) if (&from == this) return; Clear(); MergeFrom(from); } bool Example::IsInitialized() const { return true; } void Example::InternalSwap(Example* other) { using std::swap; _internal_metadata_.Swap<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(&other->_internal_metadata_); swap(features_, other->features_); } ::PROTOBUF_NAMESPACE_ID::Metadata Example::GetMetadata() const { return GetMetadataStatic(); } // =================================================================== class SequenceExample::_Internal { public: static const ::tensorflow::Features& context(const SequenceExample* msg); static const ::tensorflow::FeatureLists& feature_lists(const SequenceExample* msg); }; const ::tensorflow::Features& SequenceExample::_Internal::context(const SequenceExample* msg) { return *msg->context_; } const ::tensorflow::FeatureLists& SequenceExample::_Internal::feature_lists(const SequenceExample* msg) { return *msg->feature_lists_; } void SequenceExample::clear_context() { if (GetArena() == nullptr && context_ != nullptr) { delete context_; } context_ = nullptr; } void SequenceExample::clear_feature_lists() { if (GetArena() == nullptr && feature_lists_ != nullptr) { delete feature_lists_; } feature_lists_ = nullptr; } SequenceExample::SequenceExample(::PROTOBUF_NAMESPACE_ID::Arena* arena) : ::PROTOBUF_NAMESPACE_ID::Message(arena) { SharedCtor(); RegisterArenaDtor(arena); // @@protoc_insertion_point(arena_constructor:tensorflow.SequenceExample) } SequenceExample::SequenceExample(const SequenceExample& from) : ::PROTOBUF_NAMESPACE_ID::Message() { _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); if (from._internal_has_context()) { context_ = new ::tensorflow::Features(*from.context_); } else { context_ = nullptr; } if (from._internal_has_feature_lists()) { feature_lists_ = new ::tensorflow::FeatureLists(*from.feature_lists_); } else { feature_lists_ = nullptr; } // @@protoc_insertion_point(copy_constructor:tensorflow.SequenceExample) } void SequenceExample::SharedCtor() { ::memset(reinterpret_cast(this) + static_cast( reinterpret_cast(&context_) - reinterpret_cast(this)), 0, static_cast(reinterpret_cast(&feature_lists_) - reinterpret_cast(&context_)) + sizeof(feature_lists_)); } SequenceExample::~SequenceExample() { // @@protoc_insertion_point(destructor:tensorflow.SequenceExample) SharedDtor(); _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); } void SequenceExample::SharedDtor() { GOOGLE_DCHECK(GetArena() == nullptr); if (this != internal_default_instance()) delete context_; if (this != internal_default_instance()) delete feature_lists_; } void SequenceExample::ArenaDtor(void* object) { SequenceExample* _this = reinterpret_cast< SequenceExample* >(object); (void)_this; } void SequenceExample::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { } void SequenceExample::SetCachedSize(int size) const { _cached_size_.Set(size); } void SequenceExample::Clear() { // @@protoc_insertion_point(message_clear_start:tensorflow.SequenceExample) ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused (void) cached_has_bits; if (GetArena() == nullptr && context_ != nullptr) { delete context_; } context_ = nullptr; if (GetArena() == nullptr && feature_lists_ != nullptr) { delete feature_lists_; } feature_lists_ = nullptr; _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); } const char* SequenceExample::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure while (!ctx->Done(&ptr)) { ::PROTOBUF_NAMESPACE_ID::uint32 tag; ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); CHK_(ptr); switch (tag >> 3) { // .tensorflow.Features context = 1; case 1: if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 10)) { ptr = ctx->ParseMessage(_internal_mutable_context(), ptr); CHK_(ptr); } else goto handle_unusual; continue; // .tensorflow.FeatureLists feature_lists = 2; case 2: if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 18)) { ptr = ctx->ParseMessage(_internal_mutable_feature_lists(), ptr); CHK_(ptr); } else goto handle_unusual; continue; default: { handle_unusual: if ((tag & 7) == 4 || tag == 0) { ctx->SetLastTag(tag); goto success; } ptr = UnknownFieldParse(tag, _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), ptr, ctx); CHK_(ptr != nullptr); continue; } } // switch } // while success: return ptr; failure: ptr = nullptr; goto success; #undef CHK_ } ::PROTOBUF_NAMESPACE_ID::uint8* SequenceExample::_InternalSerialize( ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { // @@protoc_insertion_point(serialize_to_array_start:tensorflow.SequenceExample) ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; (void) cached_has_bits; // .tensorflow.Features context = 1; if (this->has_context()) { target = stream->EnsureSpace(target); target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: InternalWriteMessage( 1, _Internal::context(this), target, stream); } // .tensorflow.FeatureLists feature_lists = 2; if (this->has_feature_lists()) { target = stream->EnsureSpace(target); target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: InternalWriteMessage( 2, _Internal::feature_lists(this), target, stream); } if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); } // @@protoc_insertion_point(serialize_to_array_end:tensorflow.SequenceExample) return target; } size_t SequenceExample::ByteSizeLong() const { // @@protoc_insertion_point(message_byte_size_start:tensorflow.SequenceExample) size_t total_size = 0; ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused (void) cached_has_bits; // .tensorflow.Features context = 1; if (this->has_context()) { total_size += 1 + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( *context_); } // .tensorflow.FeatureLists feature_lists = 2; if (this->has_feature_lists()) { total_size += 1 + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( *feature_lists_); } if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize( _internal_metadata_, total_size, &_cached_size_); } int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size); SetCachedSize(cached_size); return total_size; } void SequenceExample::MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) { // @@protoc_insertion_point(generalized_merge_from_start:tensorflow.SequenceExample) GOOGLE_DCHECK_NE(&from, this); const SequenceExample* source = ::PROTOBUF_NAMESPACE_ID::DynamicCastToGenerated( &from); if (source == nullptr) { // @@protoc_insertion_point(generalized_merge_from_cast_fail:tensorflow.SequenceExample) ::PROTOBUF_NAMESPACE_ID::internal::ReflectionOps::Merge(from, this); } else { // @@protoc_insertion_point(generalized_merge_from_cast_success:tensorflow.SequenceExample) MergeFrom(*source); } } void SequenceExample::MergeFrom(const SequenceExample& from) { // @@protoc_insertion_point(class_specific_merge_from_start:tensorflow.SequenceExample) GOOGLE_DCHECK_NE(&from, this); _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; (void) cached_has_bits; if (from.has_context()) { _internal_mutable_context()->::tensorflow::Features::MergeFrom(from._internal_context()); } if (from.has_feature_lists()) { _internal_mutable_feature_lists()->::tensorflow::FeatureLists::MergeFrom(from._internal_feature_lists()); } } void SequenceExample::CopyFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) { // @@protoc_insertion_point(generalized_copy_from_start:tensorflow.SequenceExample) if (&from == this) return; Clear(); MergeFrom(from); } void SequenceExample::CopyFrom(const SequenceExample& from) { // @@protoc_insertion_point(class_specific_copy_from_start:tensorflow.SequenceExample) if (&from == this) return; Clear(); MergeFrom(from); } bool SequenceExample::IsInitialized() const { return true; } void SequenceExample::InternalSwap(SequenceExample* other) { using std::swap; _internal_metadata_.Swap<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(&other->_internal_metadata_); ::PROTOBUF_NAMESPACE_ID::internal::memswap< PROTOBUF_FIELD_OFFSET(SequenceExample, feature_lists_) + sizeof(SequenceExample::feature_lists_) - PROTOBUF_FIELD_OFFSET(SequenceExample, context_)>( reinterpret_cast(&context_), reinterpret_cast(&other->context_)); } ::PROTOBUF_NAMESPACE_ID::Metadata SequenceExample::GetMetadata() const { return GetMetadataStatic(); } // @@protoc_insertion_point(namespace_scope) } // namespace tensorflow PROTOBUF_NAMESPACE_OPEN template<> PROTOBUF_NOINLINE ::tensorflow::Example* Arena::CreateMaybeMessage< ::tensorflow::Example >(Arena* arena) { return Arena::CreateMessageInternal< ::tensorflow::Example >(arena); } template<> PROTOBUF_NOINLINE ::tensorflow::SequenceExample* Arena::CreateMaybeMessage< ::tensorflow::SequenceExample >(Arena* arena) { return Arena::CreateMessageInternal< ::tensorflow::SequenceExample >(arena); } PROTOBUF_NAMESPACE_CLOSE // @@protoc_insertion_point(global_scope) #include ================================================ FILE: src/proto/example.pb.h ================================================ // Generated by the protocol buffer compiler. DO NOT EDIT! // source: example.proto #ifndef GOOGLE_PROTOBUF_INCLUDED_example_2eproto #define GOOGLE_PROTOBUF_INCLUDED_example_2eproto #include #include #include #if PROTOBUF_VERSION < 3015000 #error This file was generated by a newer version of protoc which is #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif #if 3015000 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. #endif #include #include #include #include #include #include #include #include #include #include // IWYU pragma: export #include // IWYU pragma: export #include #include "feature.pb.h" // @@protoc_insertion_point(includes) #include #define PROTOBUF_INTERNAL_EXPORT_example_2eproto PROTOBUF_NAMESPACE_OPEN namespace internal { class AnyMetadata; } // namespace internal PROTOBUF_NAMESPACE_CLOSE // Internal implementation detail -- do not use these members. struct TableStruct_example_2eproto { static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTableField entries[] PROTOBUF_SECTION_VARIABLE(protodesc_cold); static const ::PROTOBUF_NAMESPACE_ID::internal::AuxiliaryParseTableField aux[] PROTOBUF_SECTION_VARIABLE(protodesc_cold); static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTable schema[2] PROTOBUF_SECTION_VARIABLE(protodesc_cold); static const ::PROTOBUF_NAMESPACE_ID::internal::FieldMetadata field_metadata[]; static const ::PROTOBUF_NAMESPACE_ID::internal::SerializationTable serialization_table[]; static const ::PROTOBUF_NAMESPACE_ID::uint32 offsets[]; }; extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_example_2eproto; ::PROTOBUF_NAMESPACE_ID::Metadata descriptor_table_example_2eproto_metadata_getter(int index); namespace tensorflow { class Example; struct ExampleDefaultTypeInternal; extern ExampleDefaultTypeInternal _Example_default_instance_; class SequenceExample; struct SequenceExampleDefaultTypeInternal; extern SequenceExampleDefaultTypeInternal _SequenceExample_default_instance_; } // namespace tensorflow PROTOBUF_NAMESPACE_OPEN template<> ::tensorflow::Example* Arena::CreateMaybeMessage<::tensorflow::Example>(Arena*); template<> ::tensorflow::SequenceExample* Arena::CreateMaybeMessage<::tensorflow::SequenceExample>(Arena*); PROTOBUF_NAMESPACE_CLOSE namespace tensorflow { // =================================================================== class Example PROTOBUF_FINAL : public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:tensorflow.Example) */ { public: inline Example() : Example(nullptr) {} virtual ~Example(); explicit constexpr Example(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); Example(const Example& from); Example(Example&& from) noexcept : Example() { *this = ::std::move(from); } inline Example& operator=(const Example& from) { CopyFrom(from); return *this; } inline Example& operator=(Example&& from) noexcept { if (GetArena() == from.GetArena()) { if (this != &from) InternalSwap(&from); } else { CopyFrom(from); } return *this; } static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { return GetDescriptor(); } static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { return GetMetadataStatic().descriptor; } static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { return GetMetadataStatic().reflection; } static const Example& default_instance() { return *internal_default_instance(); } static inline const Example* internal_default_instance() { return reinterpret_cast( &_Example_default_instance_); } static constexpr int kIndexInFileMessages = 0; friend void swap(Example& a, Example& b) { a.Swap(&b); } inline void Swap(Example* other) { if (other == this) return; if (GetArena() == other->GetArena()) { InternalSwap(other); } else { ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); } } void UnsafeArenaSwap(Example* other) { if (other == this) return; GOOGLE_DCHECK(GetArena() == other->GetArena()); InternalSwap(other); } // implements Message ---------------------------------------------- inline Example* New() const final { return CreateMaybeMessage(nullptr); } Example* New(::PROTOBUF_NAMESPACE_ID::Arena* arena) const final { return CreateMaybeMessage(arena); } void CopyFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) final; void MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) final; void CopyFrom(const Example& from); void MergeFrom(const Example& from); PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; bool IsInitialized() const final; size_t ByteSizeLong() const final; const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; ::PROTOBUF_NAMESPACE_ID::uint8* _InternalSerialize( ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; int GetCachedSize() const final { return _cached_size_.Get(); } private: inline void SharedCtor(); inline void SharedDtor(); void SetCachedSize(int size) const final; void InternalSwap(Example* other); friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { return "tensorflow.Example"; } protected: explicit Example(::PROTOBUF_NAMESPACE_ID::Arena* arena); private: static void ArenaDtor(void* object); inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); public: ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; private: static ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadataStatic() { return ::descriptor_table_example_2eproto_metadata_getter(kIndexInFileMessages); } public: // nested types ---------------------------------------------------- // accessors ------------------------------------------------------- enum : int { kFeaturesFieldNumber = 1, }; // .tensorflow.Features features = 1; bool has_features() const; private: bool _internal_has_features() const; public: void clear_features(); const ::tensorflow::Features& features() const; ::tensorflow::Features* release_features(); ::tensorflow::Features* mutable_features(); void set_allocated_features(::tensorflow::Features* features); private: const ::tensorflow::Features& _internal_features() const; ::tensorflow::Features* _internal_mutable_features(); public: void unsafe_arena_set_allocated_features( ::tensorflow::Features* features); ::tensorflow::Features* unsafe_arena_release_features(); // @@protoc_insertion_point(class_scope:tensorflow.Example) private: class _Internal; template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; typedef void InternalArenaConstructable_; typedef void DestructorSkippable_; ::tensorflow::Features* features_; mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; friend struct ::TableStruct_example_2eproto; }; // ------------------------------------------------------------------- class SequenceExample PROTOBUF_FINAL : public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:tensorflow.SequenceExample) */ { public: inline SequenceExample() : SequenceExample(nullptr) {} virtual ~SequenceExample(); explicit constexpr SequenceExample(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); SequenceExample(const SequenceExample& from); SequenceExample(SequenceExample&& from) noexcept : SequenceExample() { *this = ::std::move(from); } inline SequenceExample& operator=(const SequenceExample& from) { CopyFrom(from); return *this; } inline SequenceExample& operator=(SequenceExample&& from) noexcept { if (GetArena() == from.GetArena()) { if (this != &from) InternalSwap(&from); } else { CopyFrom(from); } return *this; } static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { return GetDescriptor(); } static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { return GetMetadataStatic().descriptor; } static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { return GetMetadataStatic().reflection; } static const SequenceExample& default_instance() { return *internal_default_instance(); } static inline const SequenceExample* internal_default_instance() { return reinterpret_cast( &_SequenceExample_default_instance_); } static constexpr int kIndexInFileMessages = 1; friend void swap(SequenceExample& a, SequenceExample& b) { a.Swap(&b); } inline void Swap(SequenceExample* other) { if (other == this) return; if (GetArena() == other->GetArena()) { InternalSwap(other); } else { ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); } } void UnsafeArenaSwap(SequenceExample* other) { if (other == this) return; GOOGLE_DCHECK(GetArena() == other->GetArena()); InternalSwap(other); } // implements Message ---------------------------------------------- inline SequenceExample* New() const final { return CreateMaybeMessage(nullptr); } SequenceExample* New(::PROTOBUF_NAMESPACE_ID::Arena* arena) const final { return CreateMaybeMessage(arena); } void CopyFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) final; void MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) final; void CopyFrom(const SequenceExample& from); void MergeFrom(const SequenceExample& from); PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; bool IsInitialized() const final; size_t ByteSizeLong() const final; const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; ::PROTOBUF_NAMESPACE_ID::uint8* _InternalSerialize( ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; int GetCachedSize() const final { return _cached_size_.Get(); } private: inline void SharedCtor(); inline void SharedDtor(); void SetCachedSize(int size) const final; void InternalSwap(SequenceExample* other); friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { return "tensorflow.SequenceExample"; } protected: explicit SequenceExample(::PROTOBUF_NAMESPACE_ID::Arena* arena); private: static void ArenaDtor(void* object); inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); public: ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; private: static ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadataStatic() { return ::descriptor_table_example_2eproto_metadata_getter(kIndexInFileMessages); } public: // nested types ---------------------------------------------------- // accessors ------------------------------------------------------- enum : int { kContextFieldNumber = 1, kFeatureListsFieldNumber = 2, }; // .tensorflow.Features context = 1; bool has_context() const; private: bool _internal_has_context() const; public: void clear_context(); const ::tensorflow::Features& context() const; ::tensorflow::Features* release_context(); ::tensorflow::Features* mutable_context(); void set_allocated_context(::tensorflow::Features* context); private: const ::tensorflow::Features& _internal_context() const; ::tensorflow::Features* _internal_mutable_context(); public: void unsafe_arena_set_allocated_context( ::tensorflow::Features* context); ::tensorflow::Features* unsafe_arena_release_context(); // .tensorflow.FeatureLists feature_lists = 2; bool has_feature_lists() const; private: bool _internal_has_feature_lists() const; public: void clear_feature_lists(); const ::tensorflow::FeatureLists& feature_lists() const; ::tensorflow::FeatureLists* release_feature_lists(); ::tensorflow::FeatureLists* mutable_feature_lists(); void set_allocated_feature_lists(::tensorflow::FeatureLists* feature_lists); private: const ::tensorflow::FeatureLists& _internal_feature_lists() const; ::tensorflow::FeatureLists* _internal_mutable_feature_lists(); public: void unsafe_arena_set_allocated_feature_lists( ::tensorflow::FeatureLists* feature_lists); ::tensorflow::FeatureLists* unsafe_arena_release_feature_lists(); // @@protoc_insertion_point(class_scope:tensorflow.SequenceExample) private: class _Internal; template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; typedef void InternalArenaConstructable_; typedef void DestructorSkippable_; ::tensorflow::Features* context_; ::tensorflow::FeatureLists* feature_lists_; mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; friend struct ::TableStruct_example_2eproto; }; // =================================================================== // =================================================================== #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstrict-aliasing" #endif // __GNUC__ // Example // .tensorflow.Features features = 1; inline bool Example::_internal_has_features() const { return this != internal_default_instance() && features_ != nullptr; } inline bool Example::has_features() const { return _internal_has_features(); } inline const ::tensorflow::Features& Example::_internal_features() const { const ::tensorflow::Features* p = features_; return p != nullptr ? *p : reinterpret_cast( ::tensorflow::_Features_default_instance_); } inline const ::tensorflow::Features& Example::features() const { // @@protoc_insertion_point(field_get:tensorflow.Example.features) return _internal_features(); } inline void Example::unsafe_arena_set_allocated_features( ::tensorflow::Features* features) { if (GetArena() == nullptr) { delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(features_); } features_ = features; if (features) { } else { } // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.Example.features) } inline ::tensorflow::Features* Example::release_features() { ::tensorflow::Features* temp = features_; features_ = nullptr; if (GetArena() != nullptr) { temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); } return temp; } inline ::tensorflow::Features* Example::unsafe_arena_release_features() { // @@protoc_insertion_point(field_release:tensorflow.Example.features) ::tensorflow::Features* temp = features_; features_ = nullptr; return temp; } inline ::tensorflow::Features* Example::_internal_mutable_features() { if (features_ == nullptr) { auto* p = CreateMaybeMessage<::tensorflow::Features>(GetArena()); features_ = p; } return features_; } inline ::tensorflow::Features* Example::mutable_features() { // @@protoc_insertion_point(field_mutable:tensorflow.Example.features) return _internal_mutable_features(); } inline void Example::set_allocated_features(::tensorflow::Features* features) { ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArena(); if (message_arena == nullptr) { delete reinterpret_cast< ::PROTOBUF_NAMESPACE_ID::MessageLite*>(features_); } if (features) { ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(features)->GetArena(); if (message_arena != submessage_arena) { features = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( message_arena, features, submessage_arena); } } else { } features_ = features; // @@protoc_insertion_point(field_set_allocated:tensorflow.Example.features) } // ------------------------------------------------------------------- // SequenceExample // .tensorflow.Features context = 1; inline bool SequenceExample::_internal_has_context() const { return this != internal_default_instance() && context_ != nullptr; } inline bool SequenceExample::has_context() const { return _internal_has_context(); } inline const ::tensorflow::Features& SequenceExample::_internal_context() const { const ::tensorflow::Features* p = context_; return p != nullptr ? *p : reinterpret_cast( ::tensorflow::_Features_default_instance_); } inline const ::tensorflow::Features& SequenceExample::context() const { // @@protoc_insertion_point(field_get:tensorflow.SequenceExample.context) return _internal_context(); } inline void SequenceExample::unsafe_arena_set_allocated_context( ::tensorflow::Features* context) { if (GetArena() == nullptr) { delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(context_); } context_ = context; if (context) { } else { } // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.SequenceExample.context) } inline ::tensorflow::Features* SequenceExample::release_context() { ::tensorflow::Features* temp = context_; context_ = nullptr; if (GetArena() != nullptr) { temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); } return temp; } inline ::tensorflow::Features* SequenceExample::unsafe_arena_release_context() { // @@protoc_insertion_point(field_release:tensorflow.SequenceExample.context) ::tensorflow::Features* temp = context_; context_ = nullptr; return temp; } inline ::tensorflow::Features* SequenceExample::_internal_mutable_context() { if (context_ == nullptr) { auto* p = CreateMaybeMessage<::tensorflow::Features>(GetArena()); context_ = p; } return context_; } inline ::tensorflow::Features* SequenceExample::mutable_context() { // @@protoc_insertion_point(field_mutable:tensorflow.SequenceExample.context) return _internal_mutable_context(); } inline void SequenceExample::set_allocated_context(::tensorflow::Features* context) { ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArena(); if (message_arena == nullptr) { delete reinterpret_cast< ::PROTOBUF_NAMESPACE_ID::MessageLite*>(context_); } if (context) { ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(context)->GetArena(); if (message_arena != submessage_arena) { context = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( message_arena, context, submessage_arena); } } else { } context_ = context; // @@protoc_insertion_point(field_set_allocated:tensorflow.SequenceExample.context) } // .tensorflow.FeatureLists feature_lists = 2; inline bool SequenceExample::_internal_has_feature_lists() const { return this != internal_default_instance() && feature_lists_ != nullptr; } inline bool SequenceExample::has_feature_lists() const { return _internal_has_feature_lists(); } inline const ::tensorflow::FeatureLists& SequenceExample::_internal_feature_lists() const { const ::tensorflow::FeatureLists* p = feature_lists_; return p != nullptr ? *p : reinterpret_cast( ::tensorflow::_FeatureLists_default_instance_); } inline const ::tensorflow::FeatureLists& SequenceExample::feature_lists() const { // @@protoc_insertion_point(field_get:tensorflow.SequenceExample.feature_lists) return _internal_feature_lists(); } inline void SequenceExample::unsafe_arena_set_allocated_feature_lists( ::tensorflow::FeatureLists* feature_lists) { if (GetArena() == nullptr) { delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(feature_lists_); } feature_lists_ = feature_lists; if (feature_lists) { } else { } // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.SequenceExample.feature_lists) } inline ::tensorflow::FeatureLists* SequenceExample::release_feature_lists() { ::tensorflow::FeatureLists* temp = feature_lists_; feature_lists_ = nullptr; if (GetArena() != nullptr) { temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); } return temp; } inline ::tensorflow::FeatureLists* SequenceExample::unsafe_arena_release_feature_lists() { // @@protoc_insertion_point(field_release:tensorflow.SequenceExample.feature_lists) ::tensorflow::FeatureLists* temp = feature_lists_; feature_lists_ = nullptr; return temp; } inline ::tensorflow::FeatureLists* SequenceExample::_internal_mutable_feature_lists() { if (feature_lists_ == nullptr) { auto* p = CreateMaybeMessage<::tensorflow::FeatureLists>(GetArena()); feature_lists_ = p; } return feature_lists_; } inline ::tensorflow::FeatureLists* SequenceExample::mutable_feature_lists() { // @@protoc_insertion_point(field_mutable:tensorflow.SequenceExample.feature_lists) return _internal_mutable_feature_lists(); } inline void SequenceExample::set_allocated_feature_lists(::tensorflow::FeatureLists* feature_lists) { ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArena(); if (message_arena == nullptr) { delete reinterpret_cast< ::PROTOBUF_NAMESPACE_ID::MessageLite*>(feature_lists_); } if (feature_lists) { ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(feature_lists)->GetArena(); if (message_arena != submessage_arena) { feature_lists = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( message_arena, feature_lists, submessage_arena); } } else { } feature_lists_ = feature_lists; // @@protoc_insertion_point(field_set_allocated:tensorflow.SequenceExample.feature_lists) } #ifdef __GNUC__ #pragma GCC diagnostic pop #endif // __GNUC__ // ------------------------------------------------------------------- // @@protoc_insertion_point(namespace_scope) } // namespace tensorflow // @@protoc_insertion_point(global_scope) #include #endif // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_example_2eproto ================================================ FILE: src/proto/example.proto ================================================ // Protocol messages for describing input data Examples for machine learning // model training or inference. syntax = "proto3"; package tensorflow; import "feature.proto"; option cc_enable_arenas = true; option java_outer_classname = "ExampleProtos"; option java_multiple_files = true; option java_package = "org.tensorflow.example"; option go_package = "github.com/tensorflow/tensorflow/tensorflow/go/core/example/example_protos_go_proto"; // LINT.IfChange // An Example is a mostly-normalized data format for storing data for // training and inference. It contains a key-value store (features); where // each key (string) maps to a Feature message (which is oneof packed BytesList, // FloatList, or Int64List). This flexible and compact format allows the // storage of large amounts of typed data, but requires that the data shape // and use be determined by the configuration files and parsers that are used to // read and write this format. That is, the Example is mostly *not* a // self-describing format. In TensorFlow, Examples are read in row-major // format, so any configuration that describes data with rank-2 or above // should keep this in mind. For example, to store an M x N matrix of Bytes, // the BytesList must contain M*N bytes, with M rows of N contiguous values // each. That is, the BytesList value must store the matrix as: // .... row 0 .... .... row 1 .... // ........... // ... row M-1 .... // // An Example for a movie recommendation application: // features { // feature { // key: "age" // value { float_list { // value: 29.0 // }} // } // feature { // key: "movie" // value { bytes_list { // value: "The Shawshank Redemption" // value: "Fight Club" // }} // } // feature { // key: "movie_ratings" // value { float_list { // value: 9.0 // value: 9.7 // }} // } // feature { // key: "suggestion" // value { bytes_list { // value: "Inception" // }} // } // # Note that this feature exists to be used as a label in training. // # E.g., if training a logistic regression model to predict purchase // # probability in our learning tool we would set the label feature to // # "suggestion_purchased". // feature { // key: "suggestion_purchased" // value { float_list { // value: 1.0 // }} // } // # Similar to "suggestion_purchased" above this feature exists to be used // # as a label in training. // # E.g., if training a linear regression model to predict purchase // # price in our learning tool we would set the label feature to // # "purchase_price". // feature { // key: "purchase_price" // value { float_list { // value: 9.99 // }} // } // } // // A conformant Example data set obeys the following conventions: // - If a Feature K exists in one example with data type T, it must be of // type T in all other examples when present. It may be omitted. // - The number of instances of Feature K list data may vary across examples, // depending on the requirements of the model. // - If a Feature K doesn't exist in an example, a K-specific default will be // used, if configured. // - If a Feature K exists in an example but contains no items, the intent // is considered to be an empty tensor and no default will be used. message Example { Features features = 1; } // A SequenceExample is an Example representing one or more sequences, and // some context. The context contains features which apply to the entire // example. The feature_lists contain a key, value map where each key is // associated with a repeated set of Features (a FeatureList). // A FeatureList thus represents the values of a feature identified by its key // over time / frames. // // Below is a SequenceExample for a movie recommendation application recording a // sequence of ratings by a user. The time-independent features ("locale", // "age", "favorites") describing the user are part of the context. The sequence // of movies the user rated are part of the feature_lists. For each movie in the // sequence we have information on its name and actors and the user's rating. // This information is recorded in three separate feature_list(s). // In the example below there are only two movies. All three feature_list(s), // namely "movie_ratings", "movie_names", and "actors" have a feature value for // both movies. Note, that "actors" is itself a bytes_list with multiple // strings per movie. // // context: { // feature: { // key : "locale" // value: { // bytes_list: { // value: [ "pt_BR" ] // } // } // } // feature: { // key : "age" // value: { // float_list: { // value: [ 19.0 ] // } // } // } // feature: { // key : "favorites" // value: { // bytes_list: { // value: [ "Majesty Rose", "Savannah Outen", "One Direction" ] // } // } // } // } // feature_lists: { // feature_list: { // key : "movie_ratings" // value: { // feature: { // float_list: { // value: [ 4.5 ] // } // } // feature: { // float_list: { // value: [ 5.0 ] // } // } // } // } // feature_list: { // key : "movie_names" // value: { // feature: { // bytes_list: { // value: [ "The Shawshank Redemption" ] // } // } // feature: { // bytes_list: { // value: [ "Fight Club" ] // } // } // } // } // feature_list: { // key : "actors" // value: { // feature: { // bytes_list: { // value: [ "Tim Robbins", "Morgan Freeman" ] // } // } // feature: { // bytes_list: { // value: [ "Brad Pitt", "Edward Norton", "Helena Bonham Carter" ] // } // } // } // } // } // // A conformant SequenceExample data set obeys the following conventions: // // Context: // - All conformant context features K must obey the same conventions as // a conformant Example's features (see above). // Feature lists: // - A FeatureList L may be missing in an example; it is up to the // parser configuration to determine if this is allowed or considered // an empty list (zero length). // - If a FeatureList L exists, it may be empty (zero length). // - If a FeatureList L is non-empty, all features within the FeatureList // must have the same data type T. Even across SequenceExamples, the type T // of the FeatureList identified by the same key must be the same. An entry // without any values may serve as an empty feature. // - If a FeatureList L is non-empty, it is up to the parser configuration // to determine if all features within the FeatureList must // have the same size. The same holds for this FeatureList across multiple // examples. // - For sequence modeling, e.g.: // http://colah.github.io/posts/2015-08-Understanding-LSTMs/ // https://github.com/tensorflow/nmt // the feature lists represent a sequence of frames. // In this scenario, all FeatureLists in a SequenceExample have the same // number of Feature messages, so that the ith element in each FeatureList // is part of the ith frame (or time step). // Examples of conformant and non-conformant examples' FeatureLists: // // Conformant FeatureLists: // feature_lists: { feature_list: { // key: "movie_ratings" // value: { feature: { float_list: { value: [ 4.5 ] } } // feature: { float_list: { value: [ 5.0 ] } } } // } } // // Non-conformant FeatureLists (mismatched types): // feature_lists: { feature_list: { // key: "movie_ratings" // value: { feature: { float_list: { value: [ 4.5 ] } } // feature: { int64_list: { value: [ 5 ] } } } // } } // // Conditionally conformant FeatureLists, the parser configuration determines // if the feature sizes must match: // feature_lists: { feature_list: { // key: "movie_ratings" // value: { feature: { float_list: { value: [ 4.5 ] } } // feature: { float_list: { value: [ 5.0, 6.0 ] } } } // } } // // Conformant pair of SequenceExample // feature_lists: { feature_list: { // key: "movie_ratings" // value: { feature: { float_list: { value: [ 4.5 ] } } // feature: { float_list: { value: [ 5.0 ] } } } // } } // and: // feature_lists: { feature_list: { // key: "movie_ratings" // value: { feature: { float_list: { value: [ 4.5 ] } } // feature: { float_list: { value: [ 5.0 ] } } // feature: { float_list: { value: [ 2.0 ] } } } // } } // // Conformant pair of SequenceExample // feature_lists: { feature_list: { // key: "movie_ratings" // value: { feature: { float_list: { value: [ 4.5 ] } } // feature: { float_list: { value: [ 5.0 ] } } } // } } // and: // feature_lists: { feature_list: { // key: "movie_ratings" // value: { } // } } // // Conditionally conformant pair of SequenceExample, the parser configuration // determines if the second feature_lists is consistent (zero-length) or // invalid (missing "movie_ratings"): // feature_lists: { feature_list: { // key: "movie_ratings" // value: { feature: { float_list: { value: [ 4.5 ] } } // feature: { float_list: { value: [ 5.0 ] } } } // } } // and: // feature_lists: { } // // Non-conformant pair of SequenceExample (mismatched types) // feature_lists: { feature_list: { // key: "movie_ratings" // value: { feature: { float_list: { value: [ 4.5 ] } } // feature: { float_list: { value: [ 5.0 ] } } } // } } // and: // feature_lists: { feature_list: { // key: "movie_ratings" // value: { feature: { int64_list: { value: [ 4 ] } } // feature: { int64_list: { value: [ 5 ] } } // feature: { int64_list: { value: [ 2 ] } } } // } } // // Conditionally conformant pair of SequenceExample; the parser configuration // determines if the feature sizes must match: // feature_lists: { feature_list: { // key: "movie_ratings" // value: { feature: { float_list: { value: [ 4.5 ] } } // feature: { float_list: { value: [ 5.0 ] } } } // } } // and: // feature_lists: { feature_list: { // key: "movie_ratings" // value: { feature: { float_list: { value: [ 4.0 ] } } // feature: { float_list: { value: [ 5.0, 3.0 ] } } // } } message SequenceExample { Features context = 1; FeatureLists feature_lists = 2; } // LINT.ThenChange( // https://www.tensorflow.org/code/tensorflow/python/training/training.py) ================================================ FILE: src/proto/feature.pb.cc ================================================ // Generated by the protocol buffer compiler. DO NOT EDIT! // source: feature.proto #include "feature.pb.h" #include #include #include #include #include #include #include #include // @@protoc_insertion_point(includes) #include PROTOBUF_PRAGMA_INIT_SEG namespace tensorflow { constexpr BytesList::BytesList( ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) : value_(){} struct BytesListDefaultTypeInternal { constexpr BytesListDefaultTypeInternal() : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} ~BytesListDefaultTypeInternal() {} union { BytesList _instance; }; }; PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT BytesListDefaultTypeInternal _BytesList_default_instance_; constexpr FloatList::FloatList( ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) : value_() , _value_cached_byte_size_(){} struct FloatListDefaultTypeInternal { constexpr FloatListDefaultTypeInternal() : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} ~FloatListDefaultTypeInternal() {} union { FloatList _instance; }; }; PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT FloatListDefaultTypeInternal _FloatList_default_instance_; constexpr Int64List::Int64List( ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) : value_() , _value_cached_byte_size_(){} struct Int64ListDefaultTypeInternal { constexpr Int64ListDefaultTypeInternal() : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} ~Int64ListDefaultTypeInternal() {} union { Int64List _instance; }; }; PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT Int64ListDefaultTypeInternal _Int64List_default_instance_; constexpr Feature::Feature( ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) : _oneof_case_{}{} struct FeatureDefaultTypeInternal { constexpr FeatureDefaultTypeInternal() : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} ~FeatureDefaultTypeInternal() {} union { Feature _instance; }; }; PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT FeatureDefaultTypeInternal _Feature_default_instance_; constexpr Features_FeatureEntry_DoNotUse::Features_FeatureEntry_DoNotUse( ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized){} struct Features_FeatureEntry_DoNotUseDefaultTypeInternal { constexpr Features_FeatureEntry_DoNotUseDefaultTypeInternal() : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} ~Features_FeatureEntry_DoNotUseDefaultTypeInternal() {} union { Features_FeatureEntry_DoNotUse _instance; }; }; PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT Features_FeatureEntry_DoNotUseDefaultTypeInternal _Features_FeatureEntry_DoNotUse_default_instance_; constexpr Features::Features( ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) : feature_(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}){} struct FeaturesDefaultTypeInternal { constexpr FeaturesDefaultTypeInternal() : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} ~FeaturesDefaultTypeInternal() {} union { Features _instance; }; }; PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT FeaturesDefaultTypeInternal _Features_default_instance_; constexpr FeatureList::FeatureList( ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) : feature_(){} struct FeatureListDefaultTypeInternal { constexpr FeatureListDefaultTypeInternal() : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} ~FeatureListDefaultTypeInternal() {} union { FeatureList _instance; }; }; PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT FeatureListDefaultTypeInternal _FeatureList_default_instance_; constexpr FeatureLists_FeatureListEntry_DoNotUse::FeatureLists_FeatureListEntry_DoNotUse( ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized){} struct FeatureLists_FeatureListEntry_DoNotUseDefaultTypeInternal { constexpr FeatureLists_FeatureListEntry_DoNotUseDefaultTypeInternal() : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} ~FeatureLists_FeatureListEntry_DoNotUseDefaultTypeInternal() {} union { FeatureLists_FeatureListEntry_DoNotUse _instance; }; }; PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT FeatureLists_FeatureListEntry_DoNotUseDefaultTypeInternal _FeatureLists_FeatureListEntry_DoNotUse_default_instance_; constexpr FeatureLists::FeatureLists( ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) : feature_list_(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}){} struct FeatureListsDefaultTypeInternal { constexpr FeatureListsDefaultTypeInternal() : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} ~FeatureListsDefaultTypeInternal() {} union { FeatureLists _instance; }; }; PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT FeatureListsDefaultTypeInternal _FeatureLists_default_instance_; } // namespace tensorflow static ::PROTOBUF_NAMESPACE_ID::Metadata file_level_metadata_feature_2eproto[9]; static constexpr ::PROTOBUF_NAMESPACE_ID::EnumDescriptor const** file_level_enum_descriptors_feature_2eproto = nullptr; static constexpr ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor const** file_level_service_descriptors_feature_2eproto = nullptr; const ::PROTOBUF_NAMESPACE_ID::uint32 TableStruct_feature_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { ~0u, // no _has_bits_ PROTOBUF_FIELD_OFFSET(::tensorflow::BytesList, _internal_metadata_), ~0u, // no _extensions_ ~0u, // no _oneof_case_ ~0u, // no _weak_field_map_ PROTOBUF_FIELD_OFFSET(::tensorflow::BytesList, value_), ~0u, // no _has_bits_ PROTOBUF_FIELD_OFFSET(::tensorflow::FloatList, _internal_metadata_), ~0u, // no _extensions_ ~0u, // no _oneof_case_ ~0u, // no _weak_field_map_ PROTOBUF_FIELD_OFFSET(::tensorflow::FloatList, value_), ~0u, // no _has_bits_ PROTOBUF_FIELD_OFFSET(::tensorflow::Int64List, _internal_metadata_), ~0u, // no _extensions_ ~0u, // no _oneof_case_ ~0u, // no _weak_field_map_ PROTOBUF_FIELD_OFFSET(::tensorflow::Int64List, value_), ~0u, // no _has_bits_ PROTOBUF_FIELD_OFFSET(::tensorflow::Feature, _internal_metadata_), ~0u, // no _extensions_ PROTOBUF_FIELD_OFFSET(::tensorflow::Feature, _oneof_case_[0]), ~0u, // no _weak_field_map_ ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag, ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag, ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag, PROTOBUF_FIELD_OFFSET(::tensorflow::Feature, kind_), PROTOBUF_FIELD_OFFSET(::tensorflow::Features_FeatureEntry_DoNotUse, _has_bits_), PROTOBUF_FIELD_OFFSET(::tensorflow::Features_FeatureEntry_DoNotUse, _internal_metadata_), ~0u, // no _extensions_ ~0u, // no _oneof_case_ ~0u, // no _weak_field_map_ PROTOBUF_FIELD_OFFSET(::tensorflow::Features_FeatureEntry_DoNotUse, key_), PROTOBUF_FIELD_OFFSET(::tensorflow::Features_FeatureEntry_DoNotUse, value_), 0, 1, ~0u, // no _has_bits_ PROTOBUF_FIELD_OFFSET(::tensorflow::Features, _internal_metadata_), ~0u, // no _extensions_ ~0u, // no _oneof_case_ ~0u, // no _weak_field_map_ PROTOBUF_FIELD_OFFSET(::tensorflow::Features, feature_), ~0u, // no _has_bits_ PROTOBUF_FIELD_OFFSET(::tensorflow::FeatureList, _internal_metadata_), ~0u, // no _extensions_ ~0u, // no _oneof_case_ ~0u, // no _weak_field_map_ PROTOBUF_FIELD_OFFSET(::tensorflow::FeatureList, feature_), PROTOBUF_FIELD_OFFSET(::tensorflow::FeatureLists_FeatureListEntry_DoNotUse, _has_bits_), PROTOBUF_FIELD_OFFSET(::tensorflow::FeatureLists_FeatureListEntry_DoNotUse, _internal_metadata_), ~0u, // no _extensions_ ~0u, // no _oneof_case_ ~0u, // no _weak_field_map_ PROTOBUF_FIELD_OFFSET(::tensorflow::FeatureLists_FeatureListEntry_DoNotUse, key_), PROTOBUF_FIELD_OFFSET(::tensorflow::FeatureLists_FeatureListEntry_DoNotUse, value_), 0, 1, ~0u, // no _has_bits_ PROTOBUF_FIELD_OFFSET(::tensorflow::FeatureLists, _internal_metadata_), ~0u, // no _extensions_ ~0u, // no _oneof_case_ ~0u, // no _weak_field_map_ PROTOBUF_FIELD_OFFSET(::tensorflow::FeatureLists, feature_list_), }; static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { { 0, -1, sizeof(::tensorflow::BytesList)}, { 6, -1, sizeof(::tensorflow::FloatList)}, { 12, -1, sizeof(::tensorflow::Int64List)}, { 18, -1, sizeof(::tensorflow::Feature)}, { 27, 34, sizeof(::tensorflow::Features_FeatureEntry_DoNotUse)}, { 36, -1, sizeof(::tensorflow::Features)}, { 42, -1, sizeof(::tensorflow::FeatureList)}, { 48, 55, sizeof(::tensorflow::FeatureLists_FeatureListEntry_DoNotUse)}, { 57, -1, sizeof(::tensorflow::FeatureLists)}, }; static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = { reinterpret_cast(&::tensorflow::_BytesList_default_instance_), reinterpret_cast(&::tensorflow::_FloatList_default_instance_), reinterpret_cast(&::tensorflow::_Int64List_default_instance_), reinterpret_cast(&::tensorflow::_Feature_default_instance_), reinterpret_cast(&::tensorflow::_Features_FeatureEntry_DoNotUse_default_instance_), reinterpret_cast(&::tensorflow::_Features_default_instance_), reinterpret_cast(&::tensorflow::_FeatureList_default_instance_), reinterpret_cast(&::tensorflow::_FeatureLists_FeatureListEntry_DoNotUse_default_instance_), reinterpret_cast(&::tensorflow::_FeatureLists_default_instance_), }; const char descriptor_table_protodef_feature_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = "\n\rfeature.proto\022\ntensorflow\"\032\n\tBytesList" "\022\r\n\005value\030\001 \003(\014\"\036\n\tFloatList\022\021\n\005value\030\001 " "\003(\002B\002\020\001\"\036\n\tInt64List\022\021\n\005value\030\001 \003(\003B\002\020\001\"" "\230\001\n\007Feature\022+\n\nbytes_list\030\001 \001(\0132\025.tensor" "flow.BytesListH\000\022+\n\nfloat_list\030\002 \001(\0132\025.t" "ensorflow.FloatListH\000\022+\n\nint64_list\030\003 \001(" "\0132\025.tensorflow.Int64ListH\000B\006\n\004kind\"\203\001\n\010F" "eatures\0222\n\007feature\030\001 \003(\0132!.tensorflow.Fe" "atures.FeatureEntry\032C\n\014FeatureEntry\022\013\n\003k" "ey\030\001 \001(\t\022\"\n\005value\030\002 \001(\0132\023.tensorflow.Fea" "ture:\0028\001\"3\n\013FeatureList\022$\n\007feature\030\001 \003(\013" "2\023.tensorflow.Feature\"\234\001\n\014FeatureLists\022\?" "\n\014feature_list\030\001 \003(\0132).tensorflow.Featur" "eLists.FeatureListEntry\032K\n\020FeatureListEn" "try\022\013\n\003key\030\001 \001(\t\022&\n\005value\030\002 \001(\0132\027.tensor" "flow.FeatureList:\0028\001B\201\001\n\026org.tensorflow." "exampleB\rFeatureProtosP\001ZSgithub.com/ten" "sorflow/tensorflow/tensorflow/go/core/ex" "ample/example_protos_go_proto\370\001\001b\006proto3" ; static ::PROTOBUF_NAMESPACE_ID::internal::once_flag descriptor_table_feature_2eproto_once; const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_feature_2eproto = { false, false, 760, descriptor_table_protodef_feature_2eproto, "feature.proto", &descriptor_table_feature_2eproto_once, nullptr, 0, 9, schemas, file_default_instances, TableStruct_feature_2eproto::offsets, file_level_metadata_feature_2eproto, file_level_enum_descriptors_feature_2eproto, file_level_service_descriptors_feature_2eproto, }; PROTOBUF_ATTRIBUTE_WEAK ::PROTOBUF_NAMESPACE_ID::Metadata descriptor_table_feature_2eproto_metadata_getter(int index) { ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_feature_2eproto); return descriptor_table_feature_2eproto.file_level_metadata[index]; } // Force running AddDescriptors() at dynamic initialization time. PROTOBUF_ATTRIBUTE_INIT_PRIORITY static ::PROTOBUF_NAMESPACE_ID::internal::AddDescriptorsRunner dynamic_init_dummy_feature_2eproto(&descriptor_table_feature_2eproto); namespace tensorflow { // =================================================================== class BytesList::_Internal { public: }; BytesList::BytesList(::PROTOBUF_NAMESPACE_ID::Arena* arena) : ::PROTOBUF_NAMESPACE_ID::Message(arena), value_(arena) { SharedCtor(); RegisterArenaDtor(arena); // @@protoc_insertion_point(arena_constructor:tensorflow.BytesList) } BytesList::BytesList(const BytesList& from) : ::PROTOBUF_NAMESPACE_ID::Message(), value_(from.value_) { _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); // @@protoc_insertion_point(copy_constructor:tensorflow.BytesList) } void BytesList::SharedCtor() { } BytesList::~BytesList() { // @@protoc_insertion_point(destructor:tensorflow.BytesList) SharedDtor(); _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); } void BytesList::SharedDtor() { GOOGLE_DCHECK(GetArena() == nullptr); } void BytesList::ArenaDtor(void* object) { BytesList* _this = reinterpret_cast< BytesList* >(object); (void)_this; } void BytesList::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { } void BytesList::SetCachedSize(int size) const { _cached_size_.Set(size); } void BytesList::Clear() { // @@protoc_insertion_point(message_clear_start:tensorflow.BytesList) ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused (void) cached_has_bits; value_.Clear(); _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); } const char* BytesList::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure while (!ctx->Done(&ptr)) { ::PROTOBUF_NAMESPACE_ID::uint32 tag; ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); CHK_(ptr); switch (tag >> 3) { // repeated bytes value = 1; case 1: if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 10)) { ptr -= 1; do { ptr += 1; auto str = _internal_add_value(); ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); CHK_(ptr); if (!ctx->DataAvailable(ptr)) break; } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<10>(ptr)); } else goto handle_unusual; continue; default: { handle_unusual: if ((tag & 7) == 4 || tag == 0) { ctx->SetLastTag(tag); goto success; } ptr = UnknownFieldParse(tag, _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), ptr, ctx); CHK_(ptr != nullptr); continue; } } // switch } // while success: return ptr; failure: ptr = nullptr; goto success; #undef CHK_ } ::PROTOBUF_NAMESPACE_ID::uint8* BytesList::_InternalSerialize( ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { // @@protoc_insertion_point(serialize_to_array_start:tensorflow.BytesList) ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; (void) cached_has_bits; // repeated bytes value = 1; for (int i = 0, n = this->_internal_value_size(); i < n; i++) { const auto& s = this->_internal_value(i); target = stream->WriteBytes(1, s, target); } if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); } // @@protoc_insertion_point(serialize_to_array_end:tensorflow.BytesList) return target; } size_t BytesList::ByteSizeLong() const { // @@protoc_insertion_point(message_byte_size_start:tensorflow.BytesList) size_t total_size = 0; ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused (void) cached_has_bits; // repeated bytes value = 1; total_size += 1 * ::PROTOBUF_NAMESPACE_ID::internal::FromIntSize(value_.size()); for (int i = 0, n = value_.size(); i < n; i++) { total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::BytesSize( value_.Get(i)); } if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize( _internal_metadata_, total_size, &_cached_size_); } int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size); SetCachedSize(cached_size); return total_size; } void BytesList::MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) { // @@protoc_insertion_point(generalized_merge_from_start:tensorflow.BytesList) GOOGLE_DCHECK_NE(&from, this); const BytesList* source = ::PROTOBUF_NAMESPACE_ID::DynamicCastToGenerated( &from); if (source == nullptr) { // @@protoc_insertion_point(generalized_merge_from_cast_fail:tensorflow.BytesList) ::PROTOBUF_NAMESPACE_ID::internal::ReflectionOps::Merge(from, this); } else { // @@protoc_insertion_point(generalized_merge_from_cast_success:tensorflow.BytesList) MergeFrom(*source); } } void BytesList::MergeFrom(const BytesList& from) { // @@protoc_insertion_point(class_specific_merge_from_start:tensorflow.BytesList) GOOGLE_DCHECK_NE(&from, this); _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; (void) cached_has_bits; value_.MergeFrom(from.value_); } void BytesList::CopyFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) { // @@protoc_insertion_point(generalized_copy_from_start:tensorflow.BytesList) if (&from == this) return; Clear(); MergeFrom(from); } void BytesList::CopyFrom(const BytesList& from) { // @@protoc_insertion_point(class_specific_copy_from_start:tensorflow.BytesList) if (&from == this) return; Clear(); MergeFrom(from); } bool BytesList::IsInitialized() const { return true; } void BytesList::InternalSwap(BytesList* other) { using std::swap; _internal_metadata_.Swap<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(&other->_internal_metadata_); value_.InternalSwap(&other->value_); } ::PROTOBUF_NAMESPACE_ID::Metadata BytesList::GetMetadata() const { return GetMetadataStatic(); } // =================================================================== class FloatList::_Internal { public: }; FloatList::FloatList(::PROTOBUF_NAMESPACE_ID::Arena* arena) : ::PROTOBUF_NAMESPACE_ID::Message(arena), value_(arena) { SharedCtor(); RegisterArenaDtor(arena); // @@protoc_insertion_point(arena_constructor:tensorflow.FloatList) } FloatList::FloatList(const FloatList& from) : ::PROTOBUF_NAMESPACE_ID::Message(), value_(from.value_) { _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); // @@protoc_insertion_point(copy_constructor:tensorflow.FloatList) } void FloatList::SharedCtor() { } FloatList::~FloatList() { // @@protoc_insertion_point(destructor:tensorflow.FloatList) SharedDtor(); _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); } void FloatList::SharedDtor() { GOOGLE_DCHECK(GetArena() == nullptr); } void FloatList::ArenaDtor(void* object) { FloatList* _this = reinterpret_cast< FloatList* >(object); (void)_this; } void FloatList::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { } void FloatList::SetCachedSize(int size) const { _cached_size_.Set(size); } void FloatList::Clear() { // @@protoc_insertion_point(message_clear_start:tensorflow.FloatList) ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused (void) cached_has_bits; value_.Clear(); _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); } const char* FloatList::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure while (!ctx->Done(&ptr)) { ::PROTOBUF_NAMESPACE_ID::uint32 tag; ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); CHK_(ptr); switch (tag >> 3) { // repeated float value = 1 [packed = true]; case 1: if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 10)) { ptr = ::PROTOBUF_NAMESPACE_ID::internal::PackedFloatParser(_internal_mutable_value(), ptr, ctx); CHK_(ptr); } else if (static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 13) { _internal_add_value(::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad(ptr)); ptr += sizeof(float); } else goto handle_unusual; continue; default: { handle_unusual: if ((tag & 7) == 4 || tag == 0) { ctx->SetLastTag(tag); goto success; } ptr = UnknownFieldParse(tag, _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), ptr, ctx); CHK_(ptr != nullptr); continue; } } // switch } // while success: return ptr; failure: ptr = nullptr; goto success; #undef CHK_ } ::PROTOBUF_NAMESPACE_ID::uint8* FloatList::_InternalSerialize( ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { // @@protoc_insertion_point(serialize_to_array_start:tensorflow.FloatList) ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; (void) cached_has_bits; // repeated float value = 1 [packed = true]; if (this->_internal_value_size() > 0) { target = stream->WriteFixedPacked(1, _internal_value(), target); } if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); } // @@protoc_insertion_point(serialize_to_array_end:tensorflow.FloatList) return target; } size_t FloatList::ByteSizeLong() const { // @@protoc_insertion_point(message_byte_size_start:tensorflow.FloatList) size_t total_size = 0; ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused (void) cached_has_bits; // repeated float value = 1 [packed = true]; { unsigned int count = static_cast(this->_internal_value_size()); size_t data_size = 4UL * count; if (data_size > 0) { total_size += 1 + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size( static_cast<::PROTOBUF_NAMESPACE_ID::int32>(data_size)); } int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(data_size); _value_cached_byte_size_.store(cached_size, std::memory_order_relaxed); total_size += data_size; } if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize( _internal_metadata_, total_size, &_cached_size_); } int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size); SetCachedSize(cached_size); return total_size; } void FloatList::MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) { // @@protoc_insertion_point(generalized_merge_from_start:tensorflow.FloatList) GOOGLE_DCHECK_NE(&from, this); const FloatList* source = ::PROTOBUF_NAMESPACE_ID::DynamicCastToGenerated( &from); if (source == nullptr) { // @@protoc_insertion_point(generalized_merge_from_cast_fail:tensorflow.FloatList) ::PROTOBUF_NAMESPACE_ID::internal::ReflectionOps::Merge(from, this); } else { // @@protoc_insertion_point(generalized_merge_from_cast_success:tensorflow.FloatList) MergeFrom(*source); } } void FloatList::MergeFrom(const FloatList& from) { // @@protoc_insertion_point(class_specific_merge_from_start:tensorflow.FloatList) GOOGLE_DCHECK_NE(&from, this); _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; (void) cached_has_bits; value_.MergeFrom(from.value_); } void FloatList::CopyFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) { // @@protoc_insertion_point(generalized_copy_from_start:tensorflow.FloatList) if (&from == this) return; Clear(); MergeFrom(from); } void FloatList::CopyFrom(const FloatList& from) { // @@protoc_insertion_point(class_specific_copy_from_start:tensorflow.FloatList) if (&from == this) return; Clear(); MergeFrom(from); } bool FloatList::IsInitialized() const { return true; } void FloatList::InternalSwap(FloatList* other) { using std::swap; _internal_metadata_.Swap<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(&other->_internal_metadata_); value_.InternalSwap(&other->value_); } ::PROTOBUF_NAMESPACE_ID::Metadata FloatList::GetMetadata() const { return GetMetadataStatic(); } // =================================================================== class Int64List::_Internal { public: }; Int64List::Int64List(::PROTOBUF_NAMESPACE_ID::Arena* arena) : ::PROTOBUF_NAMESPACE_ID::Message(arena), value_(arena) { SharedCtor(); RegisterArenaDtor(arena); // @@protoc_insertion_point(arena_constructor:tensorflow.Int64List) } Int64List::Int64List(const Int64List& from) : ::PROTOBUF_NAMESPACE_ID::Message(), value_(from.value_) { _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); // @@protoc_insertion_point(copy_constructor:tensorflow.Int64List) } void Int64List::SharedCtor() { } Int64List::~Int64List() { // @@protoc_insertion_point(destructor:tensorflow.Int64List) SharedDtor(); _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); } void Int64List::SharedDtor() { GOOGLE_DCHECK(GetArena() == nullptr); } void Int64List::ArenaDtor(void* object) { Int64List* _this = reinterpret_cast< Int64List* >(object); (void)_this; } void Int64List::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { } void Int64List::SetCachedSize(int size) const { _cached_size_.Set(size); } void Int64List::Clear() { // @@protoc_insertion_point(message_clear_start:tensorflow.Int64List) ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused (void) cached_has_bits; value_.Clear(); _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); } const char* Int64List::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure while (!ctx->Done(&ptr)) { ::PROTOBUF_NAMESPACE_ID::uint32 tag; ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); CHK_(ptr); switch (tag >> 3) { // repeated int64 value = 1 [packed = true]; case 1: if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 10)) { ptr = ::PROTOBUF_NAMESPACE_ID::internal::PackedInt64Parser(_internal_mutable_value(), ptr, ctx); CHK_(ptr); } else if (static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 8) { _internal_add_value(::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr)); CHK_(ptr); } else goto handle_unusual; continue; default: { handle_unusual: if ((tag & 7) == 4 || tag == 0) { ctx->SetLastTag(tag); goto success; } ptr = UnknownFieldParse(tag, _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), ptr, ctx); CHK_(ptr != nullptr); continue; } } // switch } // while success: return ptr; failure: ptr = nullptr; goto success; #undef CHK_ } ::PROTOBUF_NAMESPACE_ID::uint8* Int64List::_InternalSerialize( ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { // @@protoc_insertion_point(serialize_to_array_start:tensorflow.Int64List) ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; (void) cached_has_bits; // repeated int64 value = 1 [packed = true]; { int byte_size = _value_cached_byte_size_.load(std::memory_order_relaxed); if (byte_size > 0) { target = stream->WriteInt64Packed( 1, _internal_value(), byte_size, target); } } if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); } // @@protoc_insertion_point(serialize_to_array_end:tensorflow.Int64List) return target; } size_t Int64List::ByteSizeLong() const { // @@protoc_insertion_point(message_byte_size_start:tensorflow.Int64List) size_t total_size = 0; ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused (void) cached_has_bits; // repeated int64 value = 1 [packed = true]; { size_t data_size = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: Int64Size(this->value_); if (data_size > 0) { total_size += 1 + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size( static_cast<::PROTOBUF_NAMESPACE_ID::int32>(data_size)); } int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(data_size); _value_cached_byte_size_.store(cached_size, std::memory_order_relaxed); total_size += data_size; } if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize( _internal_metadata_, total_size, &_cached_size_); } int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size); SetCachedSize(cached_size); return total_size; } void Int64List::MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) { // @@protoc_insertion_point(generalized_merge_from_start:tensorflow.Int64List) GOOGLE_DCHECK_NE(&from, this); const Int64List* source = ::PROTOBUF_NAMESPACE_ID::DynamicCastToGenerated( &from); if (source == nullptr) { // @@protoc_insertion_point(generalized_merge_from_cast_fail:tensorflow.Int64List) ::PROTOBUF_NAMESPACE_ID::internal::ReflectionOps::Merge(from, this); } else { // @@protoc_insertion_point(generalized_merge_from_cast_success:tensorflow.Int64List) MergeFrom(*source); } } void Int64List::MergeFrom(const Int64List& from) { // @@protoc_insertion_point(class_specific_merge_from_start:tensorflow.Int64List) GOOGLE_DCHECK_NE(&from, this); _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; (void) cached_has_bits; value_.MergeFrom(from.value_); } void Int64List::CopyFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) { // @@protoc_insertion_point(generalized_copy_from_start:tensorflow.Int64List) if (&from == this) return; Clear(); MergeFrom(from); } void Int64List::CopyFrom(const Int64List& from) { // @@protoc_insertion_point(class_specific_copy_from_start:tensorflow.Int64List) if (&from == this) return; Clear(); MergeFrom(from); } bool Int64List::IsInitialized() const { return true; } void Int64List::InternalSwap(Int64List* other) { using std::swap; _internal_metadata_.Swap<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(&other->_internal_metadata_); value_.InternalSwap(&other->value_); } ::PROTOBUF_NAMESPACE_ID::Metadata Int64List::GetMetadata() const { return GetMetadataStatic(); } // =================================================================== class Feature::_Internal { public: static const ::tensorflow::BytesList& bytes_list(const Feature* msg); static const ::tensorflow::FloatList& float_list(const Feature* msg); static const ::tensorflow::Int64List& int64_list(const Feature* msg); }; const ::tensorflow::BytesList& Feature::_Internal::bytes_list(const Feature* msg) { return *msg->kind_.bytes_list_; } const ::tensorflow::FloatList& Feature::_Internal::float_list(const Feature* msg) { return *msg->kind_.float_list_; } const ::tensorflow::Int64List& Feature::_Internal::int64_list(const Feature* msg) { return *msg->kind_.int64_list_; } void Feature::set_allocated_bytes_list(::tensorflow::BytesList* bytes_list) { ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArena(); clear_kind(); if (bytes_list) { ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = ::PROTOBUF_NAMESPACE_ID::Arena::GetArena(bytes_list); if (message_arena != submessage_arena) { bytes_list = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( message_arena, bytes_list, submessage_arena); } set_has_bytes_list(); kind_.bytes_list_ = bytes_list; } // @@protoc_insertion_point(field_set_allocated:tensorflow.Feature.bytes_list) } void Feature::set_allocated_float_list(::tensorflow::FloatList* float_list) { ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArena(); clear_kind(); if (float_list) { ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = ::PROTOBUF_NAMESPACE_ID::Arena::GetArena(float_list); if (message_arena != submessage_arena) { float_list = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( message_arena, float_list, submessage_arena); } set_has_float_list(); kind_.float_list_ = float_list; } // @@protoc_insertion_point(field_set_allocated:tensorflow.Feature.float_list) } void Feature::set_allocated_int64_list(::tensorflow::Int64List* int64_list) { ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArena(); clear_kind(); if (int64_list) { ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = ::PROTOBUF_NAMESPACE_ID::Arena::GetArena(int64_list); if (message_arena != submessage_arena) { int64_list = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( message_arena, int64_list, submessage_arena); } set_has_int64_list(); kind_.int64_list_ = int64_list; } // @@protoc_insertion_point(field_set_allocated:tensorflow.Feature.int64_list) } Feature::Feature(::PROTOBUF_NAMESPACE_ID::Arena* arena) : ::PROTOBUF_NAMESPACE_ID::Message(arena) { SharedCtor(); RegisterArenaDtor(arena); // @@protoc_insertion_point(arena_constructor:tensorflow.Feature) } Feature::Feature(const Feature& from) : ::PROTOBUF_NAMESPACE_ID::Message() { _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); clear_has_kind(); switch (from.kind_case()) { case kBytesList: { _internal_mutable_bytes_list()->::tensorflow::BytesList::MergeFrom(from._internal_bytes_list()); break; } case kFloatList: { _internal_mutable_float_list()->::tensorflow::FloatList::MergeFrom(from._internal_float_list()); break; } case kInt64List: { _internal_mutable_int64_list()->::tensorflow::Int64List::MergeFrom(from._internal_int64_list()); break; } case KIND_NOT_SET: { break; } } // @@protoc_insertion_point(copy_constructor:tensorflow.Feature) } void Feature::SharedCtor() { clear_has_kind(); } Feature::~Feature() { // @@protoc_insertion_point(destructor:tensorflow.Feature) SharedDtor(); _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); } void Feature::SharedDtor() { GOOGLE_DCHECK(GetArena() == nullptr); if (has_kind()) { clear_kind(); } } void Feature::ArenaDtor(void* object) { Feature* _this = reinterpret_cast< Feature* >(object); (void)_this; } void Feature::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { } void Feature::SetCachedSize(int size) const { _cached_size_.Set(size); } void Feature::clear_kind() { // @@protoc_insertion_point(one_of_clear_start:tensorflow.Feature) switch (kind_case()) { case kBytesList: { if (GetArena() == nullptr) { delete kind_.bytes_list_; } break; } case kFloatList: { if (GetArena() == nullptr) { delete kind_.float_list_; } break; } case kInt64List: { if (GetArena() == nullptr) { delete kind_.int64_list_; } break; } case KIND_NOT_SET: { break; } } _oneof_case_[0] = KIND_NOT_SET; } void Feature::Clear() { // @@protoc_insertion_point(message_clear_start:tensorflow.Feature) ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused (void) cached_has_bits; clear_kind(); _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); } const char* Feature::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure while (!ctx->Done(&ptr)) { ::PROTOBUF_NAMESPACE_ID::uint32 tag; ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); CHK_(ptr); switch (tag >> 3) { // .tensorflow.BytesList bytes_list = 1; case 1: if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 10)) { ptr = ctx->ParseMessage(_internal_mutable_bytes_list(), ptr); CHK_(ptr); } else goto handle_unusual; continue; // .tensorflow.FloatList float_list = 2; case 2: if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 18)) { ptr = ctx->ParseMessage(_internal_mutable_float_list(), ptr); CHK_(ptr); } else goto handle_unusual; continue; // .tensorflow.Int64List int64_list = 3; case 3: if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 26)) { ptr = ctx->ParseMessage(_internal_mutable_int64_list(), ptr); CHK_(ptr); } else goto handle_unusual; continue; default: { handle_unusual: if ((tag & 7) == 4 || tag == 0) { ctx->SetLastTag(tag); goto success; } ptr = UnknownFieldParse(tag, _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), ptr, ctx); CHK_(ptr != nullptr); continue; } } // switch } // while success: return ptr; failure: ptr = nullptr; goto success; #undef CHK_ } ::PROTOBUF_NAMESPACE_ID::uint8* Feature::_InternalSerialize( ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { // @@protoc_insertion_point(serialize_to_array_start:tensorflow.Feature) ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; (void) cached_has_bits; // .tensorflow.BytesList bytes_list = 1; if (_internal_has_bytes_list()) { target = stream->EnsureSpace(target); target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: InternalWriteMessage( 1, _Internal::bytes_list(this), target, stream); } // .tensorflow.FloatList float_list = 2; if (_internal_has_float_list()) { target = stream->EnsureSpace(target); target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: InternalWriteMessage( 2, _Internal::float_list(this), target, stream); } // .tensorflow.Int64List int64_list = 3; if (_internal_has_int64_list()) { target = stream->EnsureSpace(target); target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: InternalWriteMessage( 3, _Internal::int64_list(this), target, stream); } if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); } // @@protoc_insertion_point(serialize_to_array_end:tensorflow.Feature) return target; } size_t Feature::ByteSizeLong() const { // @@protoc_insertion_point(message_byte_size_start:tensorflow.Feature) size_t total_size = 0; ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused (void) cached_has_bits; switch (kind_case()) { // .tensorflow.BytesList bytes_list = 1; case kBytesList: { total_size += 1 + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( *kind_.bytes_list_); break; } // .tensorflow.FloatList float_list = 2; case kFloatList: { total_size += 1 + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( *kind_.float_list_); break; } // .tensorflow.Int64List int64_list = 3; case kInt64List: { total_size += 1 + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( *kind_.int64_list_); break; } case KIND_NOT_SET: { break; } } if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize( _internal_metadata_, total_size, &_cached_size_); } int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size); SetCachedSize(cached_size); return total_size; } void Feature::MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) { // @@protoc_insertion_point(generalized_merge_from_start:tensorflow.Feature) GOOGLE_DCHECK_NE(&from, this); const Feature* source = ::PROTOBUF_NAMESPACE_ID::DynamicCastToGenerated( &from); if (source == nullptr) { // @@protoc_insertion_point(generalized_merge_from_cast_fail:tensorflow.Feature) ::PROTOBUF_NAMESPACE_ID::internal::ReflectionOps::Merge(from, this); } else { // @@protoc_insertion_point(generalized_merge_from_cast_success:tensorflow.Feature) MergeFrom(*source); } } void Feature::MergeFrom(const Feature& from) { // @@protoc_insertion_point(class_specific_merge_from_start:tensorflow.Feature) GOOGLE_DCHECK_NE(&from, this); _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; (void) cached_has_bits; switch (from.kind_case()) { case kBytesList: { _internal_mutable_bytes_list()->::tensorflow::BytesList::MergeFrom(from._internal_bytes_list()); break; } case kFloatList: { _internal_mutable_float_list()->::tensorflow::FloatList::MergeFrom(from._internal_float_list()); break; } case kInt64List: { _internal_mutable_int64_list()->::tensorflow::Int64List::MergeFrom(from._internal_int64_list()); break; } case KIND_NOT_SET: { break; } } } void Feature::CopyFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) { // @@protoc_insertion_point(generalized_copy_from_start:tensorflow.Feature) if (&from == this) return; Clear(); MergeFrom(from); } void Feature::CopyFrom(const Feature& from) { // @@protoc_insertion_point(class_specific_copy_from_start:tensorflow.Feature) if (&from == this) return; Clear(); MergeFrom(from); } bool Feature::IsInitialized() const { return true; } void Feature::InternalSwap(Feature* other) { using std::swap; _internal_metadata_.Swap<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(&other->_internal_metadata_); swap(kind_, other->kind_); swap(_oneof_case_[0], other->_oneof_case_[0]); } ::PROTOBUF_NAMESPACE_ID::Metadata Feature::GetMetadata() const { return GetMetadataStatic(); } // =================================================================== Features_FeatureEntry_DoNotUse::Features_FeatureEntry_DoNotUse() {} Features_FeatureEntry_DoNotUse::Features_FeatureEntry_DoNotUse(::PROTOBUF_NAMESPACE_ID::Arena* arena) : SuperType(arena) {} void Features_FeatureEntry_DoNotUse::MergeFrom(const Features_FeatureEntry_DoNotUse& other) { MergeFromInternal(other); } ::PROTOBUF_NAMESPACE_ID::Metadata Features_FeatureEntry_DoNotUse::GetMetadata() const { return GetMetadataStatic(); } void Features_FeatureEntry_DoNotUse::MergeFrom( const ::PROTOBUF_NAMESPACE_ID::Message& other) { ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom(other); } // =================================================================== class Features::_Internal { public: }; Features::Features(::PROTOBUF_NAMESPACE_ID::Arena* arena) : ::PROTOBUF_NAMESPACE_ID::Message(arena), feature_(arena) { SharedCtor(); RegisterArenaDtor(arena); // @@protoc_insertion_point(arena_constructor:tensorflow.Features) } Features::Features(const Features& from) : ::PROTOBUF_NAMESPACE_ID::Message() { _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); feature_.MergeFrom(from.feature_); // @@protoc_insertion_point(copy_constructor:tensorflow.Features) } void Features::SharedCtor() { } Features::~Features() { // @@protoc_insertion_point(destructor:tensorflow.Features) SharedDtor(); _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); } void Features::SharedDtor() { GOOGLE_DCHECK(GetArena() == nullptr); } void Features::ArenaDtor(void* object) { Features* _this = reinterpret_cast< Features* >(object); (void)_this; } void Features::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { } void Features::SetCachedSize(int size) const { _cached_size_.Set(size); } void Features::Clear() { // @@protoc_insertion_point(message_clear_start:tensorflow.Features) ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused (void) cached_has_bits; feature_.Clear(); _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); } const char* Features::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure while (!ctx->Done(&ptr)) { ::PROTOBUF_NAMESPACE_ID::uint32 tag; ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); CHK_(ptr); switch (tag >> 3) { // map feature = 1; case 1: if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 10)) { ptr -= 1; do { ptr += 1; ptr = ctx->ParseMessage(&feature_, ptr); CHK_(ptr); if (!ctx->DataAvailable(ptr)) break; } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<10>(ptr)); } else goto handle_unusual; continue; default: { handle_unusual: if ((tag & 7) == 4 || tag == 0) { ctx->SetLastTag(tag); goto success; } ptr = UnknownFieldParse(tag, _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), ptr, ctx); CHK_(ptr != nullptr); continue; } } // switch } // while success: return ptr; failure: ptr = nullptr; goto success; #undef CHK_ } ::PROTOBUF_NAMESPACE_ID::uint8* Features::_InternalSerialize( ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { // @@protoc_insertion_point(serialize_to_array_start:tensorflow.Features) ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; (void) cached_has_bits; // map feature = 1; if (!this->_internal_feature().empty()) { typedef ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::tensorflow::Feature >::const_pointer ConstPtr; typedef ConstPtr SortItem; typedef ::PROTOBUF_NAMESPACE_ID::internal::CompareByDerefFirst Less; struct Utf8Check { static void Check(ConstPtr p) { ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String( p->first.data(), static_cast(p->first.length()), ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE, "tensorflow.Features.FeatureEntry.key"); } }; if (stream->IsSerializationDeterministic() && this->_internal_feature().size() > 1) { ::std::unique_ptr items( new SortItem[this->_internal_feature().size()]); typedef ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::tensorflow::Feature >::size_type size_type; size_type n = 0; for (::PROTOBUF_NAMESPACE_ID::Map< std::string, ::tensorflow::Feature >::const_iterator it = this->_internal_feature().begin(); it != this->_internal_feature().end(); ++it, ++n) { items[static_cast(n)] = SortItem(&*it); } ::std::sort(&items[0], &items[static_cast(n)], Less()); for (size_type i = 0; i < n; i++) { target = Features_FeatureEntry_DoNotUse::Funcs::InternalSerialize(1, items[static_cast(i)]->first, items[static_cast(i)]->second, target, stream); Utf8Check::Check(&(*items[static_cast(i)])); } } else { for (::PROTOBUF_NAMESPACE_ID::Map< std::string, ::tensorflow::Feature >::const_iterator it = this->_internal_feature().begin(); it != this->_internal_feature().end(); ++it) { target = Features_FeatureEntry_DoNotUse::Funcs::InternalSerialize(1, it->first, it->second, target, stream); Utf8Check::Check(&(*it)); } } } if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); } // @@protoc_insertion_point(serialize_to_array_end:tensorflow.Features) return target; } size_t Features::ByteSizeLong() const { // @@protoc_insertion_point(message_byte_size_start:tensorflow.Features) size_t total_size = 0; ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused (void) cached_has_bits; // map feature = 1; total_size += 1 * ::PROTOBUF_NAMESPACE_ID::internal::FromIntSize(this->_internal_feature_size()); for (::PROTOBUF_NAMESPACE_ID::Map< std::string, ::tensorflow::Feature >::const_iterator it = this->_internal_feature().begin(); it != this->_internal_feature().end(); ++it) { total_size += Features_FeatureEntry_DoNotUse::Funcs::ByteSizeLong(it->first, it->second); } if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize( _internal_metadata_, total_size, &_cached_size_); } int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size); SetCachedSize(cached_size); return total_size; } void Features::MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) { // @@protoc_insertion_point(generalized_merge_from_start:tensorflow.Features) GOOGLE_DCHECK_NE(&from, this); const Features* source = ::PROTOBUF_NAMESPACE_ID::DynamicCastToGenerated( &from); if (source == nullptr) { // @@protoc_insertion_point(generalized_merge_from_cast_fail:tensorflow.Features) ::PROTOBUF_NAMESPACE_ID::internal::ReflectionOps::Merge(from, this); } else { // @@protoc_insertion_point(generalized_merge_from_cast_success:tensorflow.Features) MergeFrom(*source); } } void Features::MergeFrom(const Features& from) { // @@protoc_insertion_point(class_specific_merge_from_start:tensorflow.Features) GOOGLE_DCHECK_NE(&from, this); _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; (void) cached_has_bits; feature_.MergeFrom(from.feature_); } void Features::CopyFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) { // @@protoc_insertion_point(generalized_copy_from_start:tensorflow.Features) if (&from == this) return; Clear(); MergeFrom(from); } void Features::CopyFrom(const Features& from) { // @@protoc_insertion_point(class_specific_copy_from_start:tensorflow.Features) if (&from == this) return; Clear(); MergeFrom(from); } bool Features::IsInitialized() const { return true; } void Features::InternalSwap(Features* other) { using std::swap; _internal_metadata_.Swap<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(&other->_internal_metadata_); feature_.Swap(&other->feature_); } ::PROTOBUF_NAMESPACE_ID::Metadata Features::GetMetadata() const { return GetMetadataStatic(); } // =================================================================== class FeatureList::_Internal { public: }; FeatureList::FeatureList(::PROTOBUF_NAMESPACE_ID::Arena* arena) : ::PROTOBUF_NAMESPACE_ID::Message(arena), feature_(arena) { SharedCtor(); RegisterArenaDtor(arena); // @@protoc_insertion_point(arena_constructor:tensorflow.FeatureList) } FeatureList::FeatureList(const FeatureList& from) : ::PROTOBUF_NAMESPACE_ID::Message(), feature_(from.feature_) { _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); // @@protoc_insertion_point(copy_constructor:tensorflow.FeatureList) } void FeatureList::SharedCtor() { } FeatureList::~FeatureList() { // @@protoc_insertion_point(destructor:tensorflow.FeatureList) SharedDtor(); _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); } void FeatureList::SharedDtor() { GOOGLE_DCHECK(GetArena() == nullptr); } void FeatureList::ArenaDtor(void* object) { FeatureList* _this = reinterpret_cast< FeatureList* >(object); (void)_this; } void FeatureList::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { } void FeatureList::SetCachedSize(int size) const { _cached_size_.Set(size); } void FeatureList::Clear() { // @@protoc_insertion_point(message_clear_start:tensorflow.FeatureList) ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused (void) cached_has_bits; feature_.Clear(); _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); } const char* FeatureList::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure while (!ctx->Done(&ptr)) { ::PROTOBUF_NAMESPACE_ID::uint32 tag; ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); CHK_(ptr); switch (tag >> 3) { // repeated .tensorflow.Feature feature = 1; case 1: if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 10)) { ptr -= 1; do { ptr += 1; ptr = ctx->ParseMessage(_internal_add_feature(), ptr); CHK_(ptr); if (!ctx->DataAvailable(ptr)) break; } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<10>(ptr)); } else goto handle_unusual; continue; default: { handle_unusual: if ((tag & 7) == 4 || tag == 0) { ctx->SetLastTag(tag); goto success; } ptr = UnknownFieldParse(tag, _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), ptr, ctx); CHK_(ptr != nullptr); continue; } } // switch } // while success: return ptr; failure: ptr = nullptr; goto success; #undef CHK_ } ::PROTOBUF_NAMESPACE_ID::uint8* FeatureList::_InternalSerialize( ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { // @@protoc_insertion_point(serialize_to_array_start:tensorflow.FeatureList) ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; (void) cached_has_bits; // repeated .tensorflow.Feature feature = 1; for (unsigned int i = 0, n = static_cast(this->_internal_feature_size()); i < n; i++) { target = stream->EnsureSpace(target); target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: InternalWriteMessage(1, this->_internal_feature(i), target, stream); } if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); } // @@protoc_insertion_point(serialize_to_array_end:tensorflow.FeatureList) return target; } size_t FeatureList::ByteSizeLong() const { // @@protoc_insertion_point(message_byte_size_start:tensorflow.FeatureList) size_t total_size = 0; ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused (void) cached_has_bits; // repeated .tensorflow.Feature feature = 1; total_size += 1UL * this->_internal_feature_size(); for (const auto& msg : this->feature_) { total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg); } if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize( _internal_metadata_, total_size, &_cached_size_); } int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size); SetCachedSize(cached_size); return total_size; } void FeatureList::MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) { // @@protoc_insertion_point(generalized_merge_from_start:tensorflow.FeatureList) GOOGLE_DCHECK_NE(&from, this); const FeatureList* source = ::PROTOBUF_NAMESPACE_ID::DynamicCastToGenerated( &from); if (source == nullptr) { // @@protoc_insertion_point(generalized_merge_from_cast_fail:tensorflow.FeatureList) ::PROTOBUF_NAMESPACE_ID::internal::ReflectionOps::Merge(from, this); } else { // @@protoc_insertion_point(generalized_merge_from_cast_success:tensorflow.FeatureList) MergeFrom(*source); } } void FeatureList::MergeFrom(const FeatureList& from) { // @@protoc_insertion_point(class_specific_merge_from_start:tensorflow.FeatureList) GOOGLE_DCHECK_NE(&from, this); _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; (void) cached_has_bits; feature_.MergeFrom(from.feature_); } void FeatureList::CopyFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) { // @@protoc_insertion_point(generalized_copy_from_start:tensorflow.FeatureList) if (&from == this) return; Clear(); MergeFrom(from); } void FeatureList::CopyFrom(const FeatureList& from) { // @@protoc_insertion_point(class_specific_copy_from_start:tensorflow.FeatureList) if (&from == this) return; Clear(); MergeFrom(from); } bool FeatureList::IsInitialized() const { return true; } void FeatureList::InternalSwap(FeatureList* other) { using std::swap; _internal_metadata_.Swap<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(&other->_internal_metadata_); feature_.InternalSwap(&other->feature_); } ::PROTOBUF_NAMESPACE_ID::Metadata FeatureList::GetMetadata() const { return GetMetadataStatic(); } // =================================================================== FeatureLists_FeatureListEntry_DoNotUse::FeatureLists_FeatureListEntry_DoNotUse() {} FeatureLists_FeatureListEntry_DoNotUse::FeatureLists_FeatureListEntry_DoNotUse(::PROTOBUF_NAMESPACE_ID::Arena* arena) : SuperType(arena) {} void FeatureLists_FeatureListEntry_DoNotUse::MergeFrom(const FeatureLists_FeatureListEntry_DoNotUse& other) { MergeFromInternal(other); } ::PROTOBUF_NAMESPACE_ID::Metadata FeatureLists_FeatureListEntry_DoNotUse::GetMetadata() const { return GetMetadataStatic(); } void FeatureLists_FeatureListEntry_DoNotUse::MergeFrom( const ::PROTOBUF_NAMESPACE_ID::Message& other) { ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom(other); } // =================================================================== class FeatureLists::_Internal { public: }; FeatureLists::FeatureLists(::PROTOBUF_NAMESPACE_ID::Arena* arena) : ::PROTOBUF_NAMESPACE_ID::Message(arena), feature_list_(arena) { SharedCtor(); RegisterArenaDtor(arena); // @@protoc_insertion_point(arena_constructor:tensorflow.FeatureLists) } FeatureLists::FeatureLists(const FeatureLists& from) : ::PROTOBUF_NAMESPACE_ID::Message() { _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); feature_list_.MergeFrom(from.feature_list_); // @@protoc_insertion_point(copy_constructor:tensorflow.FeatureLists) } void FeatureLists::SharedCtor() { } FeatureLists::~FeatureLists() { // @@protoc_insertion_point(destructor:tensorflow.FeatureLists) SharedDtor(); _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); } void FeatureLists::SharedDtor() { GOOGLE_DCHECK(GetArena() == nullptr); } void FeatureLists::ArenaDtor(void* object) { FeatureLists* _this = reinterpret_cast< FeatureLists* >(object); (void)_this; } void FeatureLists::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { } void FeatureLists::SetCachedSize(int size) const { _cached_size_.Set(size); } void FeatureLists::Clear() { // @@protoc_insertion_point(message_clear_start:tensorflow.FeatureLists) ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused (void) cached_has_bits; feature_list_.Clear(); _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); } const char* FeatureLists::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure while (!ctx->Done(&ptr)) { ::PROTOBUF_NAMESPACE_ID::uint32 tag; ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); CHK_(ptr); switch (tag >> 3) { // map feature_list = 1; case 1: if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 10)) { ptr -= 1; do { ptr += 1; ptr = ctx->ParseMessage(&feature_list_, ptr); CHK_(ptr); if (!ctx->DataAvailable(ptr)) break; } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<10>(ptr)); } else goto handle_unusual; continue; default: { handle_unusual: if ((tag & 7) == 4 || tag == 0) { ctx->SetLastTag(tag); goto success; } ptr = UnknownFieldParse(tag, _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), ptr, ctx); CHK_(ptr != nullptr); continue; } } // switch } // while success: return ptr; failure: ptr = nullptr; goto success; #undef CHK_ } ::PROTOBUF_NAMESPACE_ID::uint8* FeatureLists::_InternalSerialize( ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { // @@protoc_insertion_point(serialize_to_array_start:tensorflow.FeatureLists) ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; (void) cached_has_bits; // map feature_list = 1; if (!this->_internal_feature_list().empty()) { typedef ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::tensorflow::FeatureList >::const_pointer ConstPtr; typedef ConstPtr SortItem; typedef ::PROTOBUF_NAMESPACE_ID::internal::CompareByDerefFirst Less; struct Utf8Check { static void Check(ConstPtr p) { ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String( p->first.data(), static_cast(p->first.length()), ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE, "tensorflow.FeatureLists.FeatureListEntry.key"); } }; if (stream->IsSerializationDeterministic() && this->_internal_feature_list().size() > 1) { ::std::unique_ptr items( new SortItem[this->_internal_feature_list().size()]); typedef ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::tensorflow::FeatureList >::size_type size_type; size_type n = 0; for (::PROTOBUF_NAMESPACE_ID::Map< std::string, ::tensorflow::FeatureList >::const_iterator it = this->_internal_feature_list().begin(); it != this->_internal_feature_list().end(); ++it, ++n) { items[static_cast(n)] = SortItem(&*it); } ::std::sort(&items[0], &items[static_cast(n)], Less()); for (size_type i = 0; i < n; i++) { target = FeatureLists_FeatureListEntry_DoNotUse::Funcs::InternalSerialize(1, items[static_cast(i)]->first, items[static_cast(i)]->second, target, stream); Utf8Check::Check(&(*items[static_cast(i)])); } } else { for (::PROTOBUF_NAMESPACE_ID::Map< std::string, ::tensorflow::FeatureList >::const_iterator it = this->_internal_feature_list().begin(); it != this->_internal_feature_list().end(); ++it) { target = FeatureLists_FeatureListEntry_DoNotUse::Funcs::InternalSerialize(1, it->first, it->second, target, stream); Utf8Check::Check(&(*it)); } } } if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); } // @@protoc_insertion_point(serialize_to_array_end:tensorflow.FeatureLists) return target; } size_t FeatureLists::ByteSizeLong() const { // @@protoc_insertion_point(message_byte_size_start:tensorflow.FeatureLists) size_t total_size = 0; ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused (void) cached_has_bits; // map feature_list = 1; total_size += 1 * ::PROTOBUF_NAMESPACE_ID::internal::FromIntSize(this->_internal_feature_list_size()); for (::PROTOBUF_NAMESPACE_ID::Map< std::string, ::tensorflow::FeatureList >::const_iterator it = this->_internal_feature_list().begin(); it != this->_internal_feature_list().end(); ++it) { total_size += FeatureLists_FeatureListEntry_DoNotUse::Funcs::ByteSizeLong(it->first, it->second); } if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize( _internal_metadata_, total_size, &_cached_size_); } int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size); SetCachedSize(cached_size); return total_size; } void FeatureLists::MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) { // @@protoc_insertion_point(generalized_merge_from_start:tensorflow.FeatureLists) GOOGLE_DCHECK_NE(&from, this); const FeatureLists* source = ::PROTOBUF_NAMESPACE_ID::DynamicCastToGenerated( &from); if (source == nullptr) { // @@protoc_insertion_point(generalized_merge_from_cast_fail:tensorflow.FeatureLists) ::PROTOBUF_NAMESPACE_ID::internal::ReflectionOps::Merge(from, this); } else { // @@protoc_insertion_point(generalized_merge_from_cast_success:tensorflow.FeatureLists) MergeFrom(*source); } } void FeatureLists::MergeFrom(const FeatureLists& from) { // @@protoc_insertion_point(class_specific_merge_from_start:tensorflow.FeatureLists) GOOGLE_DCHECK_NE(&from, this); _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0; (void) cached_has_bits; feature_list_.MergeFrom(from.feature_list_); } void FeatureLists::CopyFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) { // @@protoc_insertion_point(generalized_copy_from_start:tensorflow.FeatureLists) if (&from == this) return; Clear(); MergeFrom(from); } void FeatureLists::CopyFrom(const FeatureLists& from) { // @@protoc_insertion_point(class_specific_copy_from_start:tensorflow.FeatureLists) if (&from == this) return; Clear(); MergeFrom(from); } bool FeatureLists::IsInitialized() const { return true; } void FeatureLists::InternalSwap(FeatureLists* other) { using std::swap; _internal_metadata_.Swap<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(&other->_internal_metadata_); feature_list_.Swap(&other->feature_list_); } ::PROTOBUF_NAMESPACE_ID::Metadata FeatureLists::GetMetadata() const { return GetMetadataStatic(); } // @@protoc_insertion_point(namespace_scope) } // namespace tensorflow PROTOBUF_NAMESPACE_OPEN template<> PROTOBUF_NOINLINE ::tensorflow::BytesList* Arena::CreateMaybeMessage< ::tensorflow::BytesList >(Arena* arena) { return Arena::CreateMessageInternal< ::tensorflow::BytesList >(arena); } template<> PROTOBUF_NOINLINE ::tensorflow::FloatList* Arena::CreateMaybeMessage< ::tensorflow::FloatList >(Arena* arena) { return Arena::CreateMessageInternal< ::tensorflow::FloatList >(arena); } template<> PROTOBUF_NOINLINE ::tensorflow::Int64List* Arena::CreateMaybeMessage< ::tensorflow::Int64List >(Arena* arena) { return Arena::CreateMessageInternal< ::tensorflow::Int64List >(arena); } template<> PROTOBUF_NOINLINE ::tensorflow::Feature* Arena::CreateMaybeMessage< ::tensorflow::Feature >(Arena* arena) { return Arena::CreateMessageInternal< ::tensorflow::Feature >(arena); } template<> PROTOBUF_NOINLINE ::tensorflow::Features_FeatureEntry_DoNotUse* Arena::CreateMaybeMessage< ::tensorflow::Features_FeatureEntry_DoNotUse >(Arena* arena) { return Arena::CreateMessageInternal< ::tensorflow::Features_FeatureEntry_DoNotUse >(arena); } template<> PROTOBUF_NOINLINE ::tensorflow::Features* Arena::CreateMaybeMessage< ::tensorflow::Features >(Arena* arena) { return Arena::CreateMessageInternal< ::tensorflow::Features >(arena); } template<> PROTOBUF_NOINLINE ::tensorflow::FeatureList* Arena::CreateMaybeMessage< ::tensorflow::FeatureList >(Arena* arena) { return Arena::CreateMessageInternal< ::tensorflow::FeatureList >(arena); } template<> PROTOBUF_NOINLINE ::tensorflow::FeatureLists_FeatureListEntry_DoNotUse* Arena::CreateMaybeMessage< ::tensorflow::FeatureLists_FeatureListEntry_DoNotUse >(Arena* arena) { return Arena::CreateMessageInternal< ::tensorflow::FeatureLists_FeatureListEntry_DoNotUse >(arena); } template<> PROTOBUF_NOINLINE ::tensorflow::FeatureLists* Arena::CreateMaybeMessage< ::tensorflow::FeatureLists >(Arena* arena) { return Arena::CreateMessageInternal< ::tensorflow::FeatureLists >(arena); } PROTOBUF_NAMESPACE_CLOSE // @@protoc_insertion_point(global_scope) #include ================================================ FILE: src/proto/feature.pb.h ================================================ // Generated by the protocol buffer compiler. DO NOT EDIT! // source: feature.proto #ifndef GOOGLE_PROTOBUF_INCLUDED_feature_2eproto #define GOOGLE_PROTOBUF_INCLUDED_feature_2eproto #include #include #include #if PROTOBUF_VERSION < 3015000 #error This file was generated by a newer version of protoc which is #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif #if 3015000 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. #endif #include #include #include #include #include #include #include #include #include #include // IWYU pragma: export #include // IWYU pragma: export #include // IWYU pragma: export #include #include #include // @@protoc_insertion_point(includes) #include #define PROTOBUF_INTERNAL_EXPORT_feature_2eproto PROTOBUF_NAMESPACE_OPEN namespace internal { class AnyMetadata; } // namespace internal PROTOBUF_NAMESPACE_CLOSE // Internal implementation detail -- do not use these members. struct TableStruct_feature_2eproto { static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTableField entries[] PROTOBUF_SECTION_VARIABLE(protodesc_cold); static const ::PROTOBUF_NAMESPACE_ID::internal::AuxiliaryParseTableField aux[] PROTOBUF_SECTION_VARIABLE(protodesc_cold); static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTable schema[9] PROTOBUF_SECTION_VARIABLE(protodesc_cold); static const ::PROTOBUF_NAMESPACE_ID::internal::FieldMetadata field_metadata[]; static const ::PROTOBUF_NAMESPACE_ID::internal::SerializationTable serialization_table[]; static const ::PROTOBUF_NAMESPACE_ID::uint32 offsets[]; }; extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_feature_2eproto; ::PROTOBUF_NAMESPACE_ID::Metadata descriptor_table_feature_2eproto_metadata_getter(int index); namespace tensorflow { class BytesList; struct BytesListDefaultTypeInternal; extern BytesListDefaultTypeInternal _BytesList_default_instance_; class Feature; struct FeatureDefaultTypeInternal; extern FeatureDefaultTypeInternal _Feature_default_instance_; class FeatureList; struct FeatureListDefaultTypeInternal; extern FeatureListDefaultTypeInternal _FeatureList_default_instance_; class FeatureLists; struct FeatureListsDefaultTypeInternal; extern FeatureListsDefaultTypeInternal _FeatureLists_default_instance_; class FeatureLists_FeatureListEntry_DoNotUse; struct FeatureLists_FeatureListEntry_DoNotUseDefaultTypeInternal; extern FeatureLists_FeatureListEntry_DoNotUseDefaultTypeInternal _FeatureLists_FeatureListEntry_DoNotUse_default_instance_; class Features; struct FeaturesDefaultTypeInternal; extern FeaturesDefaultTypeInternal _Features_default_instance_; class Features_FeatureEntry_DoNotUse; struct Features_FeatureEntry_DoNotUseDefaultTypeInternal; extern Features_FeatureEntry_DoNotUseDefaultTypeInternal _Features_FeatureEntry_DoNotUse_default_instance_; class FloatList; struct FloatListDefaultTypeInternal; extern FloatListDefaultTypeInternal _FloatList_default_instance_; class Int64List; struct Int64ListDefaultTypeInternal; extern Int64ListDefaultTypeInternal _Int64List_default_instance_; } // namespace tensorflow PROTOBUF_NAMESPACE_OPEN template<> ::tensorflow::BytesList* Arena::CreateMaybeMessage<::tensorflow::BytesList>(Arena*); template<> ::tensorflow::Feature* Arena::CreateMaybeMessage<::tensorflow::Feature>(Arena*); template<> ::tensorflow::FeatureList* Arena::CreateMaybeMessage<::tensorflow::FeatureList>(Arena*); template<> ::tensorflow::FeatureLists* Arena::CreateMaybeMessage<::tensorflow::FeatureLists>(Arena*); template<> ::tensorflow::FeatureLists_FeatureListEntry_DoNotUse* Arena::CreateMaybeMessage<::tensorflow::FeatureLists_FeatureListEntry_DoNotUse>(Arena*); template<> ::tensorflow::Features* Arena::CreateMaybeMessage<::tensorflow::Features>(Arena*); template<> ::tensorflow::Features_FeatureEntry_DoNotUse* Arena::CreateMaybeMessage<::tensorflow::Features_FeatureEntry_DoNotUse>(Arena*); template<> ::tensorflow::FloatList* Arena::CreateMaybeMessage<::tensorflow::FloatList>(Arena*); template<> ::tensorflow::Int64List* Arena::CreateMaybeMessage<::tensorflow::Int64List>(Arena*); PROTOBUF_NAMESPACE_CLOSE namespace tensorflow { // =================================================================== class BytesList PROTOBUF_FINAL : public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:tensorflow.BytesList) */ { public: inline BytesList() : BytesList(nullptr) {} virtual ~BytesList(); explicit constexpr BytesList(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); BytesList(const BytesList& from); BytesList(BytesList&& from) noexcept : BytesList() { *this = ::std::move(from); } inline BytesList& operator=(const BytesList& from) { CopyFrom(from); return *this; } inline BytesList& operator=(BytesList&& from) noexcept { if (GetArena() == from.GetArena()) { if (this != &from) InternalSwap(&from); } else { CopyFrom(from); } return *this; } static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { return GetDescriptor(); } static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { return GetMetadataStatic().descriptor; } static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { return GetMetadataStatic().reflection; } static const BytesList& default_instance() { return *internal_default_instance(); } static inline const BytesList* internal_default_instance() { return reinterpret_cast( &_BytesList_default_instance_); } static constexpr int kIndexInFileMessages = 0; friend void swap(BytesList& a, BytesList& b) { a.Swap(&b); } inline void Swap(BytesList* other) { if (other == this) return; if (GetArena() == other->GetArena()) { InternalSwap(other); } else { ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); } } void UnsafeArenaSwap(BytesList* other) { if (other == this) return; GOOGLE_DCHECK(GetArena() == other->GetArena()); InternalSwap(other); } // implements Message ---------------------------------------------- inline BytesList* New() const final { return CreateMaybeMessage(nullptr); } BytesList* New(::PROTOBUF_NAMESPACE_ID::Arena* arena) const final { return CreateMaybeMessage(arena); } void CopyFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) final; void MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) final; void CopyFrom(const BytesList& from); void MergeFrom(const BytesList& from); PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; bool IsInitialized() const final; size_t ByteSizeLong() const final; const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; ::PROTOBUF_NAMESPACE_ID::uint8* _InternalSerialize( ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; int GetCachedSize() const final { return _cached_size_.Get(); } private: inline void SharedCtor(); inline void SharedDtor(); void SetCachedSize(int size) const final; void InternalSwap(BytesList* other); friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { return "tensorflow.BytesList"; } protected: explicit BytesList(::PROTOBUF_NAMESPACE_ID::Arena* arena); private: static void ArenaDtor(void* object); inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); public: ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; private: static ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadataStatic() { return ::descriptor_table_feature_2eproto_metadata_getter(kIndexInFileMessages); } public: // nested types ---------------------------------------------------- // accessors ------------------------------------------------------- enum : int { kValueFieldNumber = 1, }; // repeated bytes value = 1; int value_size() const; private: int _internal_value_size() const; public: void clear_value(); const std::string& value(int index) const; std::string* mutable_value(int index); void set_value(int index, const std::string& value); void set_value(int index, std::string&& value); void set_value(int index, const char* value); void set_value(int index, const void* value, size_t size); std::string* add_value(); void add_value(const std::string& value); void add_value(std::string&& value); void add_value(const char* value); void add_value(const void* value, size_t size); const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField& value() const; ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField* mutable_value(); private: const std::string& _internal_value(int index) const; std::string* _internal_add_value(); public: // @@protoc_insertion_point(class_scope:tensorflow.BytesList) private: class _Internal; template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; typedef void InternalArenaConstructable_; typedef void DestructorSkippable_; ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField value_; mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; friend struct ::TableStruct_feature_2eproto; }; // ------------------------------------------------------------------- class FloatList PROTOBUF_FINAL : public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:tensorflow.FloatList) */ { public: inline FloatList() : FloatList(nullptr) {} virtual ~FloatList(); explicit constexpr FloatList(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); FloatList(const FloatList& from); FloatList(FloatList&& from) noexcept : FloatList() { *this = ::std::move(from); } inline FloatList& operator=(const FloatList& from) { CopyFrom(from); return *this; } inline FloatList& operator=(FloatList&& from) noexcept { if (GetArena() == from.GetArena()) { if (this != &from) InternalSwap(&from); } else { CopyFrom(from); } return *this; } static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { return GetDescriptor(); } static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { return GetMetadataStatic().descriptor; } static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { return GetMetadataStatic().reflection; } static const FloatList& default_instance() { return *internal_default_instance(); } static inline const FloatList* internal_default_instance() { return reinterpret_cast( &_FloatList_default_instance_); } static constexpr int kIndexInFileMessages = 1; friend void swap(FloatList& a, FloatList& b) { a.Swap(&b); } inline void Swap(FloatList* other) { if (other == this) return; if (GetArena() == other->GetArena()) { InternalSwap(other); } else { ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); } } void UnsafeArenaSwap(FloatList* other) { if (other == this) return; GOOGLE_DCHECK(GetArena() == other->GetArena()); InternalSwap(other); } // implements Message ---------------------------------------------- inline FloatList* New() const final { return CreateMaybeMessage(nullptr); } FloatList* New(::PROTOBUF_NAMESPACE_ID::Arena* arena) const final { return CreateMaybeMessage(arena); } void CopyFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) final; void MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) final; void CopyFrom(const FloatList& from); void MergeFrom(const FloatList& from); PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; bool IsInitialized() const final; size_t ByteSizeLong() const final; const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; ::PROTOBUF_NAMESPACE_ID::uint8* _InternalSerialize( ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; int GetCachedSize() const final { return _cached_size_.Get(); } private: inline void SharedCtor(); inline void SharedDtor(); void SetCachedSize(int size) const final; void InternalSwap(FloatList* other); friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { return "tensorflow.FloatList"; } protected: explicit FloatList(::PROTOBUF_NAMESPACE_ID::Arena* arena); private: static void ArenaDtor(void* object); inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); public: ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; private: static ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadataStatic() { return ::descriptor_table_feature_2eproto_metadata_getter(kIndexInFileMessages); } public: // nested types ---------------------------------------------------- // accessors ------------------------------------------------------- enum : int { kValueFieldNumber = 1, }; // repeated float value = 1 [packed = true]; int value_size() const; private: int _internal_value_size() const; public: void clear_value(); private: float _internal_value(int index) const; const ::PROTOBUF_NAMESPACE_ID::RepeatedField< float >& _internal_value() const; void _internal_add_value(float value); ::PROTOBUF_NAMESPACE_ID::RepeatedField< float >* _internal_mutable_value(); public: float value(int index) const; void set_value(int index, float value); void add_value(float value); const ::PROTOBUF_NAMESPACE_ID::RepeatedField< float >& value() const; ::PROTOBUF_NAMESPACE_ID::RepeatedField< float >* mutable_value(); // @@protoc_insertion_point(class_scope:tensorflow.FloatList) private: class _Internal; template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; typedef void InternalArenaConstructable_; typedef void DestructorSkippable_; ::PROTOBUF_NAMESPACE_ID::RepeatedField< float > value_; mutable std::atomic _value_cached_byte_size_; mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; friend struct ::TableStruct_feature_2eproto; }; // ------------------------------------------------------------------- class Int64List PROTOBUF_FINAL : public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:tensorflow.Int64List) */ { public: inline Int64List() : Int64List(nullptr) {} virtual ~Int64List(); explicit constexpr Int64List(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); Int64List(const Int64List& from); Int64List(Int64List&& from) noexcept : Int64List() { *this = ::std::move(from); } inline Int64List& operator=(const Int64List& from) { CopyFrom(from); return *this; } inline Int64List& operator=(Int64List&& from) noexcept { if (GetArena() == from.GetArena()) { if (this != &from) InternalSwap(&from); } else { CopyFrom(from); } return *this; } static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { return GetDescriptor(); } static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { return GetMetadataStatic().descriptor; } static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { return GetMetadataStatic().reflection; } static const Int64List& default_instance() { return *internal_default_instance(); } static inline const Int64List* internal_default_instance() { return reinterpret_cast( &_Int64List_default_instance_); } static constexpr int kIndexInFileMessages = 2; friend void swap(Int64List& a, Int64List& b) { a.Swap(&b); } inline void Swap(Int64List* other) { if (other == this) return; if (GetArena() == other->GetArena()) { InternalSwap(other); } else { ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); } } void UnsafeArenaSwap(Int64List* other) { if (other == this) return; GOOGLE_DCHECK(GetArena() == other->GetArena()); InternalSwap(other); } // implements Message ---------------------------------------------- inline Int64List* New() const final { return CreateMaybeMessage(nullptr); } Int64List* New(::PROTOBUF_NAMESPACE_ID::Arena* arena) const final { return CreateMaybeMessage(arena); } void CopyFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) final; void MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) final; void CopyFrom(const Int64List& from); void MergeFrom(const Int64List& from); PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; bool IsInitialized() const final; size_t ByteSizeLong() const final; const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; ::PROTOBUF_NAMESPACE_ID::uint8* _InternalSerialize( ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; int GetCachedSize() const final { return _cached_size_.Get(); } private: inline void SharedCtor(); inline void SharedDtor(); void SetCachedSize(int size) const final; void InternalSwap(Int64List* other); friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { return "tensorflow.Int64List"; } protected: explicit Int64List(::PROTOBUF_NAMESPACE_ID::Arena* arena); private: static void ArenaDtor(void* object); inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); public: ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; private: static ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadataStatic() { return ::descriptor_table_feature_2eproto_metadata_getter(kIndexInFileMessages); } public: // nested types ---------------------------------------------------- // accessors ------------------------------------------------------- enum : int { kValueFieldNumber = 1, }; // repeated int64 value = 1 [packed = true]; int value_size() const; private: int _internal_value_size() const; public: void clear_value(); private: ::PROTOBUF_NAMESPACE_ID::int64 _internal_value(int index) const; const ::PROTOBUF_NAMESPACE_ID::RepeatedField< ::PROTOBUF_NAMESPACE_ID::int64 >& _internal_value() const; void _internal_add_value(::PROTOBUF_NAMESPACE_ID::int64 value); ::PROTOBUF_NAMESPACE_ID::RepeatedField< ::PROTOBUF_NAMESPACE_ID::int64 >* _internal_mutable_value(); public: ::PROTOBUF_NAMESPACE_ID::int64 value(int index) const; void set_value(int index, ::PROTOBUF_NAMESPACE_ID::int64 value); void add_value(::PROTOBUF_NAMESPACE_ID::int64 value); const ::PROTOBUF_NAMESPACE_ID::RepeatedField< ::PROTOBUF_NAMESPACE_ID::int64 >& value() const; ::PROTOBUF_NAMESPACE_ID::RepeatedField< ::PROTOBUF_NAMESPACE_ID::int64 >* mutable_value(); // @@protoc_insertion_point(class_scope:tensorflow.Int64List) private: class _Internal; template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; typedef void InternalArenaConstructable_; typedef void DestructorSkippable_; ::PROTOBUF_NAMESPACE_ID::RepeatedField< ::PROTOBUF_NAMESPACE_ID::int64 > value_; mutable std::atomic _value_cached_byte_size_; mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; friend struct ::TableStruct_feature_2eproto; }; // ------------------------------------------------------------------- class Feature PROTOBUF_FINAL : public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:tensorflow.Feature) */ { public: inline Feature() : Feature(nullptr) {} virtual ~Feature(); explicit constexpr Feature(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); Feature(const Feature& from); Feature(Feature&& from) noexcept : Feature() { *this = ::std::move(from); } inline Feature& operator=(const Feature& from) { CopyFrom(from); return *this; } inline Feature& operator=(Feature&& from) noexcept { if (GetArena() == from.GetArena()) { if (this != &from) InternalSwap(&from); } else { CopyFrom(from); } return *this; } static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { return GetDescriptor(); } static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { return GetMetadataStatic().descriptor; } static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { return GetMetadataStatic().reflection; } static const Feature& default_instance() { return *internal_default_instance(); } enum KindCase { kBytesList = 1, kFloatList = 2, kInt64List = 3, KIND_NOT_SET = 0, }; static inline const Feature* internal_default_instance() { return reinterpret_cast( &_Feature_default_instance_); } static constexpr int kIndexInFileMessages = 3; friend void swap(Feature& a, Feature& b) { a.Swap(&b); } inline void Swap(Feature* other) { if (other == this) return; if (GetArena() == other->GetArena()) { InternalSwap(other); } else { ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); } } void UnsafeArenaSwap(Feature* other) { if (other == this) return; GOOGLE_DCHECK(GetArena() == other->GetArena()); InternalSwap(other); } // implements Message ---------------------------------------------- inline Feature* New() const final { return CreateMaybeMessage(nullptr); } Feature* New(::PROTOBUF_NAMESPACE_ID::Arena* arena) const final { return CreateMaybeMessage(arena); } void CopyFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) final; void MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) final; void CopyFrom(const Feature& from); void MergeFrom(const Feature& from); PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; bool IsInitialized() const final; size_t ByteSizeLong() const final; const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; ::PROTOBUF_NAMESPACE_ID::uint8* _InternalSerialize( ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; int GetCachedSize() const final { return _cached_size_.Get(); } private: inline void SharedCtor(); inline void SharedDtor(); void SetCachedSize(int size) const final; void InternalSwap(Feature* other); friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { return "tensorflow.Feature"; } protected: explicit Feature(::PROTOBUF_NAMESPACE_ID::Arena* arena); private: static void ArenaDtor(void* object); inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); public: ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; private: static ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadataStatic() { return ::descriptor_table_feature_2eproto_metadata_getter(kIndexInFileMessages); } public: // nested types ---------------------------------------------------- // accessors ------------------------------------------------------- enum : int { kBytesListFieldNumber = 1, kFloatListFieldNumber = 2, kInt64ListFieldNumber = 3, }; // .tensorflow.BytesList bytes_list = 1; bool has_bytes_list() const; private: bool _internal_has_bytes_list() const; public: void clear_bytes_list(); const ::tensorflow::BytesList& bytes_list() const; ::tensorflow::BytesList* release_bytes_list(); ::tensorflow::BytesList* mutable_bytes_list(); void set_allocated_bytes_list(::tensorflow::BytesList* bytes_list); private: const ::tensorflow::BytesList& _internal_bytes_list() const; ::tensorflow::BytesList* _internal_mutable_bytes_list(); public: void unsafe_arena_set_allocated_bytes_list( ::tensorflow::BytesList* bytes_list); ::tensorflow::BytesList* unsafe_arena_release_bytes_list(); // .tensorflow.FloatList float_list = 2; bool has_float_list() const; private: bool _internal_has_float_list() const; public: void clear_float_list(); const ::tensorflow::FloatList& float_list() const; ::tensorflow::FloatList* release_float_list(); ::tensorflow::FloatList* mutable_float_list(); void set_allocated_float_list(::tensorflow::FloatList* float_list); private: const ::tensorflow::FloatList& _internal_float_list() const; ::tensorflow::FloatList* _internal_mutable_float_list(); public: void unsafe_arena_set_allocated_float_list( ::tensorflow::FloatList* float_list); ::tensorflow::FloatList* unsafe_arena_release_float_list(); // .tensorflow.Int64List int64_list = 3; bool has_int64_list() const; private: bool _internal_has_int64_list() const; public: void clear_int64_list(); const ::tensorflow::Int64List& int64_list() const; ::tensorflow::Int64List* release_int64_list(); ::tensorflow::Int64List* mutable_int64_list(); void set_allocated_int64_list(::tensorflow::Int64List* int64_list); private: const ::tensorflow::Int64List& _internal_int64_list() const; ::tensorflow::Int64List* _internal_mutable_int64_list(); public: void unsafe_arena_set_allocated_int64_list( ::tensorflow::Int64List* int64_list); ::tensorflow::Int64List* unsafe_arena_release_int64_list(); void clear_kind(); KindCase kind_case() const; // @@protoc_insertion_point(class_scope:tensorflow.Feature) private: class _Internal; void set_has_bytes_list(); void set_has_float_list(); void set_has_int64_list(); inline bool has_kind() const; inline void clear_has_kind(); template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; typedef void InternalArenaConstructable_; typedef void DestructorSkippable_; union KindUnion { constexpr KindUnion() : _constinit_{} {} ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized _constinit_; ::tensorflow::BytesList* bytes_list_; ::tensorflow::FloatList* float_list_; ::tensorflow::Int64List* int64_list_; } kind_; mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; ::PROTOBUF_NAMESPACE_ID::uint32 _oneof_case_[1]; friend struct ::TableStruct_feature_2eproto; }; // ------------------------------------------------------------------- class Features_FeatureEntry_DoNotUse : public ::PROTOBUF_NAMESPACE_ID::internal::MapEntry { public: typedef ::PROTOBUF_NAMESPACE_ID::internal::MapEntry SuperType; Features_FeatureEntry_DoNotUse(); explicit constexpr Features_FeatureEntry_DoNotUse( ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); explicit Features_FeatureEntry_DoNotUse(::PROTOBUF_NAMESPACE_ID::Arena* arena); void MergeFrom(const Features_FeatureEntry_DoNotUse& other); static const Features_FeatureEntry_DoNotUse* internal_default_instance() { return reinterpret_cast(&_Features_FeatureEntry_DoNotUse_default_instance_); } static bool ValidateKey(std::string* s) { return ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(s->data(), static_cast(s->size()), ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::PARSE, "tensorflow.Features.FeatureEntry.key"); } static bool ValidateValue(void*) { return true; } void MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& other) final; ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; private: static ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadataStatic() { ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&::descriptor_table_feature_2eproto); return ::descriptor_table_feature_2eproto.file_level_metadata[4]; } public: }; // ------------------------------------------------------------------- class Features PROTOBUF_FINAL : public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:tensorflow.Features) */ { public: inline Features() : Features(nullptr) {} virtual ~Features(); explicit constexpr Features(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); Features(const Features& from); Features(Features&& from) noexcept : Features() { *this = ::std::move(from); } inline Features& operator=(const Features& from) { CopyFrom(from); return *this; } inline Features& operator=(Features&& from) noexcept { if (GetArena() == from.GetArena()) { if (this != &from) InternalSwap(&from); } else { CopyFrom(from); } return *this; } static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { return GetDescriptor(); } static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { return GetMetadataStatic().descriptor; } static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { return GetMetadataStatic().reflection; } static const Features& default_instance() { return *internal_default_instance(); } static inline const Features* internal_default_instance() { return reinterpret_cast( &_Features_default_instance_); } static constexpr int kIndexInFileMessages = 5; friend void swap(Features& a, Features& b) { a.Swap(&b); } inline void Swap(Features* other) { if (other == this) return; if (GetArena() == other->GetArena()) { InternalSwap(other); } else { ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); } } void UnsafeArenaSwap(Features* other) { if (other == this) return; GOOGLE_DCHECK(GetArena() == other->GetArena()); InternalSwap(other); } // implements Message ---------------------------------------------- inline Features* New() const final { return CreateMaybeMessage(nullptr); } Features* New(::PROTOBUF_NAMESPACE_ID::Arena* arena) const final { return CreateMaybeMessage(arena); } void CopyFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) final; void MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) final; void CopyFrom(const Features& from); void MergeFrom(const Features& from); PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; bool IsInitialized() const final; size_t ByteSizeLong() const final; const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; ::PROTOBUF_NAMESPACE_ID::uint8* _InternalSerialize( ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; int GetCachedSize() const final { return _cached_size_.Get(); } private: inline void SharedCtor(); inline void SharedDtor(); void SetCachedSize(int size) const final; void InternalSwap(Features* other); friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { return "tensorflow.Features"; } protected: explicit Features(::PROTOBUF_NAMESPACE_ID::Arena* arena); private: static void ArenaDtor(void* object); inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); public: ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; private: static ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadataStatic() { return ::descriptor_table_feature_2eproto_metadata_getter(kIndexInFileMessages); } public: // nested types ---------------------------------------------------- // accessors ------------------------------------------------------- enum : int { kFeatureFieldNumber = 1, }; // map feature = 1; int feature_size() const; private: int _internal_feature_size() const; public: void clear_feature(); private: const ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::tensorflow::Feature >& _internal_feature() const; ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::tensorflow::Feature >* _internal_mutable_feature(); public: const ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::tensorflow::Feature >& feature() const; ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::tensorflow::Feature >* mutable_feature(); // @@protoc_insertion_point(class_scope:tensorflow.Features) private: class _Internal; template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; typedef void InternalArenaConstructable_; typedef void DestructorSkippable_; ::PROTOBUF_NAMESPACE_ID::internal::MapField< Features_FeatureEntry_DoNotUse, std::string, ::tensorflow::Feature, ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::TYPE_STRING, ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::TYPE_MESSAGE> feature_; mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; friend struct ::TableStruct_feature_2eproto; }; // ------------------------------------------------------------------- class FeatureList PROTOBUF_FINAL : public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:tensorflow.FeatureList) */ { public: inline FeatureList() : FeatureList(nullptr) {} virtual ~FeatureList(); explicit constexpr FeatureList(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); FeatureList(const FeatureList& from); FeatureList(FeatureList&& from) noexcept : FeatureList() { *this = ::std::move(from); } inline FeatureList& operator=(const FeatureList& from) { CopyFrom(from); return *this; } inline FeatureList& operator=(FeatureList&& from) noexcept { if (GetArena() == from.GetArena()) { if (this != &from) InternalSwap(&from); } else { CopyFrom(from); } return *this; } static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { return GetDescriptor(); } static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { return GetMetadataStatic().descriptor; } static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { return GetMetadataStatic().reflection; } static const FeatureList& default_instance() { return *internal_default_instance(); } static inline const FeatureList* internal_default_instance() { return reinterpret_cast( &_FeatureList_default_instance_); } static constexpr int kIndexInFileMessages = 6; friend void swap(FeatureList& a, FeatureList& b) { a.Swap(&b); } inline void Swap(FeatureList* other) { if (other == this) return; if (GetArena() == other->GetArena()) { InternalSwap(other); } else { ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); } } void UnsafeArenaSwap(FeatureList* other) { if (other == this) return; GOOGLE_DCHECK(GetArena() == other->GetArena()); InternalSwap(other); } // implements Message ---------------------------------------------- inline FeatureList* New() const final { return CreateMaybeMessage(nullptr); } FeatureList* New(::PROTOBUF_NAMESPACE_ID::Arena* arena) const final { return CreateMaybeMessage(arena); } void CopyFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) final; void MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) final; void CopyFrom(const FeatureList& from); void MergeFrom(const FeatureList& from); PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; bool IsInitialized() const final; size_t ByteSizeLong() const final; const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; ::PROTOBUF_NAMESPACE_ID::uint8* _InternalSerialize( ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; int GetCachedSize() const final { return _cached_size_.Get(); } private: inline void SharedCtor(); inline void SharedDtor(); void SetCachedSize(int size) const final; void InternalSwap(FeatureList* other); friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { return "tensorflow.FeatureList"; } protected: explicit FeatureList(::PROTOBUF_NAMESPACE_ID::Arena* arena); private: static void ArenaDtor(void* object); inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); public: ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; private: static ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadataStatic() { return ::descriptor_table_feature_2eproto_metadata_getter(kIndexInFileMessages); } public: // nested types ---------------------------------------------------- // accessors ------------------------------------------------------- enum : int { kFeatureFieldNumber = 1, }; // repeated .tensorflow.Feature feature = 1; int feature_size() const; private: int _internal_feature_size() const; public: void clear_feature(); ::tensorflow::Feature* mutable_feature(int index); ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::tensorflow::Feature >* mutable_feature(); private: const ::tensorflow::Feature& _internal_feature(int index) const; ::tensorflow::Feature* _internal_add_feature(); public: const ::tensorflow::Feature& feature(int index) const; ::tensorflow::Feature* add_feature(); const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::tensorflow::Feature >& feature() const; // @@protoc_insertion_point(class_scope:tensorflow.FeatureList) private: class _Internal; template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; typedef void InternalArenaConstructable_; typedef void DestructorSkippable_; ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::tensorflow::Feature > feature_; mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; friend struct ::TableStruct_feature_2eproto; }; // ------------------------------------------------------------------- class FeatureLists_FeatureListEntry_DoNotUse : public ::PROTOBUF_NAMESPACE_ID::internal::MapEntry { public: typedef ::PROTOBUF_NAMESPACE_ID::internal::MapEntry SuperType; FeatureLists_FeatureListEntry_DoNotUse(); explicit constexpr FeatureLists_FeatureListEntry_DoNotUse( ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); explicit FeatureLists_FeatureListEntry_DoNotUse(::PROTOBUF_NAMESPACE_ID::Arena* arena); void MergeFrom(const FeatureLists_FeatureListEntry_DoNotUse& other); static const FeatureLists_FeatureListEntry_DoNotUse* internal_default_instance() { return reinterpret_cast(&_FeatureLists_FeatureListEntry_DoNotUse_default_instance_); } static bool ValidateKey(std::string* s) { return ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(s->data(), static_cast(s->size()), ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::PARSE, "tensorflow.FeatureLists.FeatureListEntry.key"); } static bool ValidateValue(void*) { return true; } void MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& other) final; ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; private: static ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadataStatic() { ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&::descriptor_table_feature_2eproto); return ::descriptor_table_feature_2eproto.file_level_metadata[7]; } public: }; // ------------------------------------------------------------------- class FeatureLists PROTOBUF_FINAL : public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:tensorflow.FeatureLists) */ { public: inline FeatureLists() : FeatureLists(nullptr) {} virtual ~FeatureLists(); explicit constexpr FeatureLists(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); FeatureLists(const FeatureLists& from); FeatureLists(FeatureLists&& from) noexcept : FeatureLists() { *this = ::std::move(from); } inline FeatureLists& operator=(const FeatureLists& from) { CopyFrom(from); return *this; } inline FeatureLists& operator=(FeatureLists&& from) noexcept { if (GetArena() == from.GetArena()) { if (this != &from) InternalSwap(&from); } else { CopyFrom(from); } return *this; } static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { return GetDescriptor(); } static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { return GetMetadataStatic().descriptor; } static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { return GetMetadataStatic().reflection; } static const FeatureLists& default_instance() { return *internal_default_instance(); } static inline const FeatureLists* internal_default_instance() { return reinterpret_cast( &_FeatureLists_default_instance_); } static constexpr int kIndexInFileMessages = 8; friend void swap(FeatureLists& a, FeatureLists& b) { a.Swap(&b); } inline void Swap(FeatureLists* other) { if (other == this) return; if (GetArena() == other->GetArena()) { InternalSwap(other); } else { ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); } } void UnsafeArenaSwap(FeatureLists* other) { if (other == this) return; GOOGLE_DCHECK(GetArena() == other->GetArena()); InternalSwap(other); } // implements Message ---------------------------------------------- inline FeatureLists* New() const final { return CreateMaybeMessage(nullptr); } FeatureLists* New(::PROTOBUF_NAMESPACE_ID::Arena* arena) const final { return CreateMaybeMessage(arena); } void CopyFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) final; void MergeFrom(const ::PROTOBUF_NAMESPACE_ID::Message& from) final; void CopyFrom(const FeatureLists& from); void MergeFrom(const FeatureLists& from); PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; bool IsInitialized() const final; size_t ByteSizeLong() const final; const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; ::PROTOBUF_NAMESPACE_ID::uint8* _InternalSerialize( ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; int GetCachedSize() const final { return _cached_size_.Get(); } private: inline void SharedCtor(); inline void SharedDtor(); void SetCachedSize(int size) const final; void InternalSwap(FeatureLists* other); friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { return "tensorflow.FeatureLists"; } protected: explicit FeatureLists(::PROTOBUF_NAMESPACE_ID::Arena* arena); private: static void ArenaDtor(void* object); inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); public: ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; private: static ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadataStatic() { return ::descriptor_table_feature_2eproto_metadata_getter(kIndexInFileMessages); } public: // nested types ---------------------------------------------------- // accessors ------------------------------------------------------- enum : int { kFeatureListFieldNumber = 1, }; // map feature_list = 1; int feature_list_size() const; private: int _internal_feature_list_size() const; public: void clear_feature_list(); private: const ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::tensorflow::FeatureList >& _internal_feature_list() const; ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::tensorflow::FeatureList >* _internal_mutable_feature_list(); public: const ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::tensorflow::FeatureList >& feature_list() const; ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::tensorflow::FeatureList >* mutable_feature_list(); // @@protoc_insertion_point(class_scope:tensorflow.FeatureLists) private: class _Internal; template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; typedef void InternalArenaConstructable_; typedef void DestructorSkippable_; ::PROTOBUF_NAMESPACE_ID::internal::MapField< FeatureLists_FeatureListEntry_DoNotUse, std::string, ::tensorflow::FeatureList, ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::TYPE_STRING, ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::TYPE_MESSAGE> feature_list_; mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; friend struct ::TableStruct_feature_2eproto; }; // =================================================================== // =================================================================== #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstrict-aliasing" #endif // __GNUC__ // BytesList // repeated bytes value = 1; inline int BytesList::_internal_value_size() const { return value_.size(); } inline int BytesList::value_size() const { return _internal_value_size(); } inline void BytesList::clear_value() { value_.Clear(); } inline std::string* BytesList::add_value() { // @@protoc_insertion_point(field_add_mutable:tensorflow.BytesList.value) return _internal_add_value(); } inline const std::string& BytesList::_internal_value(int index) const { return value_.Get(index); } inline const std::string& BytesList::value(int index) const { // @@protoc_insertion_point(field_get:tensorflow.BytesList.value) return _internal_value(index); } inline std::string* BytesList::mutable_value(int index) { // @@protoc_insertion_point(field_mutable:tensorflow.BytesList.value) return value_.Mutable(index); } inline void BytesList::set_value(int index, const std::string& value) { // @@protoc_insertion_point(field_set:tensorflow.BytesList.value) value_.Mutable(index)->assign(value); } inline void BytesList::set_value(int index, std::string&& value) { // @@protoc_insertion_point(field_set:tensorflow.BytesList.value) value_.Mutable(index)->assign(std::move(value)); } inline void BytesList::set_value(int index, const char* value) { GOOGLE_DCHECK(value != nullptr); value_.Mutable(index)->assign(value); // @@protoc_insertion_point(field_set_char:tensorflow.BytesList.value) } inline void BytesList::set_value(int index, const void* value, size_t size) { value_.Mutable(index)->assign( reinterpret_cast(value), size); // @@protoc_insertion_point(field_set_pointer:tensorflow.BytesList.value) } inline std::string* BytesList::_internal_add_value() { return value_.Add(); } inline void BytesList::add_value(const std::string& value) { value_.Add()->assign(value); // @@protoc_insertion_point(field_add:tensorflow.BytesList.value) } inline void BytesList::add_value(std::string&& value) { value_.Add(std::move(value)); // @@protoc_insertion_point(field_add:tensorflow.BytesList.value) } inline void BytesList::add_value(const char* value) { GOOGLE_DCHECK(value != nullptr); value_.Add()->assign(value); // @@protoc_insertion_point(field_add_char:tensorflow.BytesList.value) } inline void BytesList::add_value(const void* value, size_t size) { value_.Add()->assign(reinterpret_cast(value), size); // @@protoc_insertion_point(field_add_pointer:tensorflow.BytesList.value) } inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField& BytesList::value() const { // @@protoc_insertion_point(field_list:tensorflow.BytesList.value) return value_; } inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField* BytesList::mutable_value() { // @@protoc_insertion_point(field_mutable_list:tensorflow.BytesList.value) return &value_; } // ------------------------------------------------------------------- // FloatList // repeated float value = 1 [packed = true]; inline int FloatList::_internal_value_size() const { return value_.size(); } inline int FloatList::value_size() const { return _internal_value_size(); } inline void FloatList::clear_value() { value_.Clear(); } inline float FloatList::_internal_value(int index) const { return value_.Get(index); } inline float FloatList::value(int index) const { // @@protoc_insertion_point(field_get:tensorflow.FloatList.value) return _internal_value(index); } inline void FloatList::set_value(int index, float value) { value_.Set(index, value); // @@protoc_insertion_point(field_set:tensorflow.FloatList.value) } inline void FloatList::_internal_add_value(float value) { value_.Add(value); } inline void FloatList::add_value(float value) { _internal_add_value(value); // @@protoc_insertion_point(field_add:tensorflow.FloatList.value) } inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< float >& FloatList::_internal_value() const { return value_; } inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< float >& FloatList::value() const { // @@protoc_insertion_point(field_list:tensorflow.FloatList.value) return _internal_value(); } inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< float >* FloatList::_internal_mutable_value() { return &value_; } inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< float >* FloatList::mutable_value() { // @@protoc_insertion_point(field_mutable_list:tensorflow.FloatList.value) return _internal_mutable_value(); } // ------------------------------------------------------------------- // Int64List // repeated int64 value = 1 [packed = true]; inline int Int64List::_internal_value_size() const { return value_.size(); } inline int Int64List::value_size() const { return _internal_value_size(); } inline void Int64List::clear_value() { value_.Clear(); } inline ::PROTOBUF_NAMESPACE_ID::int64 Int64List::_internal_value(int index) const { return value_.Get(index); } inline ::PROTOBUF_NAMESPACE_ID::int64 Int64List::value(int index) const { // @@protoc_insertion_point(field_get:tensorflow.Int64List.value) return _internal_value(index); } inline void Int64List::set_value(int index, ::PROTOBUF_NAMESPACE_ID::int64 value) { value_.Set(index, value); // @@protoc_insertion_point(field_set:tensorflow.Int64List.value) } inline void Int64List::_internal_add_value(::PROTOBUF_NAMESPACE_ID::int64 value) { value_.Add(value); } inline void Int64List::add_value(::PROTOBUF_NAMESPACE_ID::int64 value) { _internal_add_value(value); // @@protoc_insertion_point(field_add:tensorflow.Int64List.value) } inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< ::PROTOBUF_NAMESPACE_ID::int64 >& Int64List::_internal_value() const { return value_; } inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< ::PROTOBUF_NAMESPACE_ID::int64 >& Int64List::value() const { // @@protoc_insertion_point(field_list:tensorflow.Int64List.value) return _internal_value(); } inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< ::PROTOBUF_NAMESPACE_ID::int64 >* Int64List::_internal_mutable_value() { return &value_; } inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< ::PROTOBUF_NAMESPACE_ID::int64 >* Int64List::mutable_value() { // @@protoc_insertion_point(field_mutable_list:tensorflow.Int64List.value) return _internal_mutable_value(); } // ------------------------------------------------------------------- // Feature // .tensorflow.BytesList bytes_list = 1; inline bool Feature::_internal_has_bytes_list() const { return kind_case() == kBytesList; } inline bool Feature::has_bytes_list() const { return _internal_has_bytes_list(); } inline void Feature::set_has_bytes_list() { _oneof_case_[0] = kBytesList; } inline void Feature::clear_bytes_list() { if (_internal_has_bytes_list()) { if (GetArena() == nullptr) { delete kind_.bytes_list_; } clear_has_kind(); } } inline ::tensorflow::BytesList* Feature::release_bytes_list() { // @@protoc_insertion_point(field_release:tensorflow.Feature.bytes_list) if (_internal_has_bytes_list()) { clear_has_kind(); ::tensorflow::BytesList* temp = kind_.bytes_list_; if (GetArena() != nullptr) { temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); } kind_.bytes_list_ = nullptr; return temp; } else { return nullptr; } } inline const ::tensorflow::BytesList& Feature::_internal_bytes_list() const { return _internal_has_bytes_list() ? *kind_.bytes_list_ : reinterpret_cast< ::tensorflow::BytesList&>(::tensorflow::_BytesList_default_instance_); } inline const ::tensorflow::BytesList& Feature::bytes_list() const { // @@protoc_insertion_point(field_get:tensorflow.Feature.bytes_list) return _internal_bytes_list(); } inline ::tensorflow::BytesList* Feature::unsafe_arena_release_bytes_list() { // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.Feature.bytes_list) if (_internal_has_bytes_list()) { clear_has_kind(); ::tensorflow::BytesList* temp = kind_.bytes_list_; kind_.bytes_list_ = nullptr; return temp; } else { return nullptr; } } inline void Feature::unsafe_arena_set_allocated_bytes_list(::tensorflow::BytesList* bytes_list) { clear_kind(); if (bytes_list) { set_has_bytes_list(); kind_.bytes_list_ = bytes_list; } // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.Feature.bytes_list) } inline ::tensorflow::BytesList* Feature::_internal_mutable_bytes_list() { if (!_internal_has_bytes_list()) { clear_kind(); set_has_bytes_list(); kind_.bytes_list_ = CreateMaybeMessage< ::tensorflow::BytesList >(GetArena()); } return kind_.bytes_list_; } inline ::tensorflow::BytesList* Feature::mutable_bytes_list() { // @@protoc_insertion_point(field_mutable:tensorflow.Feature.bytes_list) return _internal_mutable_bytes_list(); } // .tensorflow.FloatList float_list = 2; inline bool Feature::_internal_has_float_list() const { return kind_case() == kFloatList; } inline bool Feature::has_float_list() const { return _internal_has_float_list(); } inline void Feature::set_has_float_list() { _oneof_case_[0] = kFloatList; } inline void Feature::clear_float_list() { if (_internal_has_float_list()) { if (GetArena() == nullptr) { delete kind_.float_list_; } clear_has_kind(); } } inline ::tensorflow::FloatList* Feature::release_float_list() { // @@protoc_insertion_point(field_release:tensorflow.Feature.float_list) if (_internal_has_float_list()) { clear_has_kind(); ::tensorflow::FloatList* temp = kind_.float_list_; if (GetArena() != nullptr) { temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); } kind_.float_list_ = nullptr; return temp; } else { return nullptr; } } inline const ::tensorflow::FloatList& Feature::_internal_float_list() const { return _internal_has_float_list() ? *kind_.float_list_ : reinterpret_cast< ::tensorflow::FloatList&>(::tensorflow::_FloatList_default_instance_); } inline const ::tensorflow::FloatList& Feature::float_list() const { // @@protoc_insertion_point(field_get:tensorflow.Feature.float_list) return _internal_float_list(); } inline ::tensorflow::FloatList* Feature::unsafe_arena_release_float_list() { // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.Feature.float_list) if (_internal_has_float_list()) { clear_has_kind(); ::tensorflow::FloatList* temp = kind_.float_list_; kind_.float_list_ = nullptr; return temp; } else { return nullptr; } } inline void Feature::unsafe_arena_set_allocated_float_list(::tensorflow::FloatList* float_list) { clear_kind(); if (float_list) { set_has_float_list(); kind_.float_list_ = float_list; } // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.Feature.float_list) } inline ::tensorflow::FloatList* Feature::_internal_mutable_float_list() { if (!_internal_has_float_list()) { clear_kind(); set_has_float_list(); kind_.float_list_ = CreateMaybeMessage< ::tensorflow::FloatList >(GetArena()); } return kind_.float_list_; } inline ::tensorflow::FloatList* Feature::mutable_float_list() { // @@protoc_insertion_point(field_mutable:tensorflow.Feature.float_list) return _internal_mutable_float_list(); } // .tensorflow.Int64List int64_list = 3; inline bool Feature::_internal_has_int64_list() const { return kind_case() == kInt64List; } inline bool Feature::has_int64_list() const { return _internal_has_int64_list(); } inline void Feature::set_has_int64_list() { _oneof_case_[0] = kInt64List; } inline void Feature::clear_int64_list() { if (_internal_has_int64_list()) { if (GetArena() == nullptr) { delete kind_.int64_list_; } clear_has_kind(); } } inline ::tensorflow::Int64List* Feature::release_int64_list() { // @@protoc_insertion_point(field_release:tensorflow.Feature.int64_list) if (_internal_has_int64_list()) { clear_has_kind(); ::tensorflow::Int64List* temp = kind_.int64_list_; if (GetArena() != nullptr) { temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); } kind_.int64_list_ = nullptr; return temp; } else { return nullptr; } } inline const ::tensorflow::Int64List& Feature::_internal_int64_list() const { return _internal_has_int64_list() ? *kind_.int64_list_ : reinterpret_cast< ::tensorflow::Int64List&>(::tensorflow::_Int64List_default_instance_); } inline const ::tensorflow::Int64List& Feature::int64_list() const { // @@protoc_insertion_point(field_get:tensorflow.Feature.int64_list) return _internal_int64_list(); } inline ::tensorflow::Int64List* Feature::unsafe_arena_release_int64_list() { // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.Feature.int64_list) if (_internal_has_int64_list()) { clear_has_kind(); ::tensorflow::Int64List* temp = kind_.int64_list_; kind_.int64_list_ = nullptr; return temp; } else { return nullptr; } } inline void Feature::unsafe_arena_set_allocated_int64_list(::tensorflow::Int64List* int64_list) { clear_kind(); if (int64_list) { set_has_int64_list(); kind_.int64_list_ = int64_list; } // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.Feature.int64_list) } inline ::tensorflow::Int64List* Feature::_internal_mutable_int64_list() { if (!_internal_has_int64_list()) { clear_kind(); set_has_int64_list(); kind_.int64_list_ = CreateMaybeMessage< ::tensorflow::Int64List >(GetArena()); } return kind_.int64_list_; } inline ::tensorflow::Int64List* Feature::mutable_int64_list() { // @@protoc_insertion_point(field_mutable:tensorflow.Feature.int64_list) return _internal_mutable_int64_list(); } inline bool Feature::has_kind() const { return kind_case() != KIND_NOT_SET; } inline void Feature::clear_has_kind() { _oneof_case_[0] = KIND_NOT_SET; } inline Feature::KindCase Feature::kind_case() const { return Feature::KindCase(_oneof_case_[0]); } // ------------------------------------------------------------------- // ------------------------------------------------------------------- // Features // map feature = 1; inline int Features::_internal_feature_size() const { return feature_.size(); } inline int Features::feature_size() const { return _internal_feature_size(); } inline void Features::clear_feature() { feature_.Clear(); } inline const ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::tensorflow::Feature >& Features::_internal_feature() const { return feature_.GetMap(); } inline const ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::tensorflow::Feature >& Features::feature() const { // @@protoc_insertion_point(field_map:tensorflow.Features.feature) return _internal_feature(); } inline ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::tensorflow::Feature >* Features::_internal_mutable_feature() { return feature_.MutableMap(); } inline ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::tensorflow::Feature >* Features::mutable_feature() { // @@protoc_insertion_point(field_mutable_map:tensorflow.Features.feature) return _internal_mutable_feature(); } // ------------------------------------------------------------------- // FeatureList // repeated .tensorflow.Feature feature = 1; inline int FeatureList::_internal_feature_size() const { return feature_.size(); } inline int FeatureList::feature_size() const { return _internal_feature_size(); } inline void FeatureList::clear_feature() { feature_.Clear(); } inline ::tensorflow::Feature* FeatureList::mutable_feature(int index) { // @@protoc_insertion_point(field_mutable:tensorflow.FeatureList.feature) return feature_.Mutable(index); } inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::tensorflow::Feature >* FeatureList::mutable_feature() { // @@protoc_insertion_point(field_mutable_list:tensorflow.FeatureList.feature) return &feature_; } inline const ::tensorflow::Feature& FeatureList::_internal_feature(int index) const { return feature_.Get(index); } inline const ::tensorflow::Feature& FeatureList::feature(int index) const { // @@protoc_insertion_point(field_get:tensorflow.FeatureList.feature) return _internal_feature(index); } inline ::tensorflow::Feature* FeatureList::_internal_add_feature() { return feature_.Add(); } inline ::tensorflow::Feature* FeatureList::add_feature() { // @@protoc_insertion_point(field_add:tensorflow.FeatureList.feature) return _internal_add_feature(); } inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::tensorflow::Feature >& FeatureList::feature() const { // @@protoc_insertion_point(field_list:tensorflow.FeatureList.feature) return feature_; } // ------------------------------------------------------------------- // ------------------------------------------------------------------- // FeatureLists // map feature_list = 1; inline int FeatureLists::_internal_feature_list_size() const { return feature_list_.size(); } inline int FeatureLists::feature_list_size() const { return _internal_feature_list_size(); } inline void FeatureLists::clear_feature_list() { feature_list_.Clear(); } inline const ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::tensorflow::FeatureList >& FeatureLists::_internal_feature_list() const { return feature_list_.GetMap(); } inline const ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::tensorflow::FeatureList >& FeatureLists::feature_list() const { // @@protoc_insertion_point(field_map:tensorflow.FeatureLists.feature_list) return _internal_feature_list(); } inline ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::tensorflow::FeatureList >* FeatureLists::_internal_mutable_feature_list() { return feature_list_.MutableMap(); } inline ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::tensorflow::FeatureList >* FeatureLists::mutable_feature_list() { // @@protoc_insertion_point(field_mutable_map:tensorflow.FeatureLists.feature_list) return _internal_mutable_feature_list(); } #ifdef __GNUC__ #pragma GCC diagnostic pop #endif // __GNUC__ // ------------------------------------------------------------------- // ------------------------------------------------------------------- // ------------------------------------------------------------------- // ------------------------------------------------------------------- // ------------------------------------------------------------------- // ------------------------------------------------------------------- // ------------------------------------------------------------------- // ------------------------------------------------------------------- // @@protoc_insertion_point(namespace_scope) } // namespace tensorflow // @@protoc_insertion_point(global_scope) #include #endif // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_feature_2eproto ================================================ FILE: src/proto/feature.proto ================================================ // Protocol messages for describing features for machine learning model // training or inference. // // There are three base Feature types: // - bytes // - float // - int64 // // A Feature contains Lists which may hold zero or more values. These // lists are the base values BytesList, FloatList, Int64List. // // Features are organized into categories by name. The Features message // contains the mapping from name to Feature. // // Example Features for a movie recommendation application: // feature { // key: "age" // value { float_list { // value: 29.0 // }} // } // feature { // key: "movie" // value { bytes_list { // value: "The Shawshank Redemption" // value: "Fight Club" // }} // } // feature { // key: "movie_ratings" // value { float_list { // value: 9.0 // value: 9.7 // }} // } // feature { // key: "suggestion" // value { bytes_list { // value: "Inception" // }} // } // feature { // key: "suggestion_purchased" // value { int64_list { // value: 1 // }} // } // feature { // key: "purchase_price" // value { float_list { // value: 9.99 // }} // } // syntax = "proto3"; package tensorflow; option cc_enable_arenas = true; option java_outer_classname = "FeatureProtos"; option java_multiple_files = true; option java_package = "org.tensorflow.example"; option go_package = "github.com/tensorflow/tensorflow/tensorflow/go/core/example/example_protos_go_proto"; // LINT.IfChange // Containers to hold repeated fundamental values. message BytesList { repeated bytes value = 1; } message FloatList { repeated float value = 1 [packed = true]; } message Int64List { repeated int64 value = 1 [packed = true]; } // Containers for non-sequential data. message Feature { // Each feature can be exactly one kind. oneof kind { BytesList bytes_list = 1; FloatList float_list = 2; Int64List int64_list = 3; } } message Features { // Map from feature name to feature. map feature = 1; } // Containers for sequential data. // // A FeatureList contains lists of Features. These may hold zero or more // Feature values. // // FeatureLists are organized into categories by name. The FeatureLists message // contains the mapping from name to FeatureList. // message FeatureList { repeated Feature feature = 1; } message FeatureLists { // Map from feature name to feature list. map feature_list = 1; } // LINT.ThenChange( // https://www.tensorflow.org/code/tensorflow/python/training/training.py) ================================================ FILE: src/refinerangedialog.cpp ================================================ #include "refinerangedialog.h" #include "ui_refinerangedialog.h" RefineRangeDialog::RefineRangeDialog(QWidget *parent) : QDialog(parent), ui(new Ui::RefineRangeDialog) { ui->setupUi(this); setWindowModality(Qt::WindowModal); connect(ui->startSpinBox, SIGNAL(valueChanged(int)), this, SLOT(check())); connect(ui->endSpinBox, SIGNAL(valueChanged(int)), this, SLOT(check())); } void RefineRangeDialog::setMaxImage(int max_images){ ui->startSpinBox->setRange(1, max_images+1); ui->endSpinBox->setRange(1, max_images+1); } int RefineRangeDialog::getStart(){ return ui->startSpinBox->value(); } int RefineRangeDialog::getEnd(){ return ui->endSpinBox->value(); } void RefineRangeDialog::setCurrentImage(int i){ ui->startSpinBox->setValue(i); ui->endSpinBox->setValue(i); } bool RefineRangeDialog::check(){ ui->buttonBox->button(QDialogButtonBox::Ok)->setDisabled(true); if(getStart() > getEnd()) return false; ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); return true; } RefineRangeDialog::~RefineRangeDialog() { delete ui; } ================================================ FILE: src/refinerangedialog.h ================================================ #ifndef REFINERANGEDIALOG_H #define REFINERANGEDIALOG_H #include #include namespace Ui { class RefineRangeDialog; } class RefineRangeDialog : public QDialog { Q_OBJECT public: explicit RefineRangeDialog(QWidget *parent = nullptr); ~RefineRangeDialog(); int getStart(); int getEnd(); public slots: void setMaxImage(int max_images); void setCurrentImage(int i); private slots: bool check(); private: Ui::RefineRangeDialog *ui; }; #endif // REFINERANGEDIALOG_H ================================================ FILE: src/refinerangedialog.ui ================================================ RefineRangeDialog 0 0 349 109 Dialog Start image: End image: Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() RefineRangeDialog accept() 248 254 157 274 buttonBox rejected() RefineRangeDialog reject() 316 260 286 274 ================================================ FILE: src/tfrecordexporter.cpp ================================================ #include "tfrecordexporter.h" void TFRecordExporter::generateLabelIds(const QString names_file){ id_map.clear(); // Force sort list QStringList class_list; QFile fh(names_file); if (fh.open(QIODevice::ReadOnly)) { while (!fh.atEnd()) { // Darknet name file is just a newline delimited list of classes QByteArray line = fh.readLine(); class_list.append(line); } } if(class_list.size() == 0){ qWarning() << "No classes found in names file."; return; } int i = 1; // 0 is background for(auto &name : class_list){ auto cleaned_name = name.simplified().toLower(); id_map[cleaned_name] = i++; qDebug() << "Adding: " << cleaned_name << " (" << i << ")"; } } void TFRecordExporter::add_int64_feature(tensorflow::Features &features, std::string key, std::vector values){ auto map = features.mutable_feature(); for(auto value : values){ (*map)[key].mutable_int64_list()->add_value(value); } } void TFRecordExporter::add_bytes_feature(tensorflow::Features &features, std::string key, std::vector values, std::vector sizes){ auto map = features.mutable_feature(); for(size_t i=0; i < values.size(); ++i){ (*map)[key].mutable_bytes_list()->add_value(static_cast(values.at(i)), sizes.at(i)); } } void TFRecordExporter::add_bytes_feature(tensorflow::Features &features, std::string key, std::vector values){ auto map = features.mutable_feature(); for(auto &value : values){ (*map)[key].mutable_bytes_list()->add_value(value); } } void TFRecordExporter::add_float_feature(tensorflow::Features &features, std::string key, std::vector values){ auto map = features.mutable_feature(); for(auto value : values){ (*map)[key].mutable_float_list()->add_value(value); } } void TFRecordExporter::create_weights(){ QMap counts; project->getClassCounts(counts); int n_class = counts.size(); int total_labels = 0; for(auto class_id : counts.keys()){ total_labels += counts[class_id]; } float total_weight = 0; for(auto class_id : counts.keys()){ weight_map[class_id] = total_labels / counts[class_id]; total_weight += weight_map[class_id]; } for(auto &class_id : weight_map.keys()){ weight_map[class_id] = weight_map[class_id]/total_weight * n_class; qInfo() << "Set weight for class " << class_id << "to: " << weight_map[class_id]; } } bool TFRecordExporter::create_example(tensorflow::Example &example, QString image_path) { QList labels; project->getLabels(image_path, labels); if(labels.size() == 0 && !export_unlabelled){ return false; }else{ qInfo() << "Processing " << image_path; } auto db_dir = project->getDbFolder(); auto abs_path = QFileInfo(QDir::cleanPath(db_dir.filePath(image_path))).absoluteFilePath(); QFile image(abs_path); image.open(QIODevice::ReadOnly); QByteArray buffer = image.readAll(); auto im = cv::imdecode(cv::Mat(1, buffer.size(), CV_8UC1, buffer.data()), cv::IMREAD_UNCHANGED); auto image_ext = QFileInfo(image_path).suffix(); tensorflow::Features features; // Image data add_int64_feature(features, "image/width", {im.cols}); add_int64_feature(features, "image/height", {im.rows}); add_bytes_feature(features, "image/filename", {image_path.toStdString()}); add_bytes_feature(features, "image/source_id", {QString("%1").arg(qHash(image_path)).toStdString()}); add_bytes_feature(features, "image/format", {image_ext.toStdString()}); add_bytes_feature(features, "image/encoded", {buffer.data()}, {static_cast(buffer.size())}); image.close(); std::vector xmins; std::vector xmaxs; std::vector ymins; std::vector ymaxs; std::vector classes_text; std::vector classes; std::vector class_weights; for(auto &label : labels){ // Check if this label exists in the database if(id_map.find(label.classname.toLower()) == id_map.end()){ qWarning() << "Couldn't find this label in the names file: " << label.classname.toLower(); continue; } xmins.push_back(label.rect.left()); xmaxs.push_back(label.rect.right()); ymins.push_back(label.rect.bottom()); ymaxs.push_back(label.rect.top()); classes_text.push_back(label.classname.toStdString()); classes.push_back(id_map[label.classname]); class_weights.push_back(weight_map[id_map[label.classname]]); } // Bounding boxes add_float_feature(features, "image/object/bbox/xmin", xmins); add_float_feature(features, "image/object/bbox/xmax", xmaxs ); add_float_feature(features, "image/object/bbox/ymin", ymins ); add_float_feature(features, "image/object/bbox/ymaxs", ymaxs ); add_bytes_feature(features, "image/object/class/text", classes_text ); add_int64_feature(features, "image/object/class/label", classes ); //add_float_feature(features, "image/object/weight", class_weights ); *example.mutable_features() = features; return true; } void TFRecordExporter::setNumberShards(int n){ number_shards = n; } bool TFRecordExporter::processImages(const QString folder, const QString record_prefix, const QList images, export_image_type split_type){ QString image_path; QList labels; QProgressDialog progress("...", "Abort", 0, images.size(), static_cast(parent())); progress.setWindowModality(Qt::WindowModal); if(folder == ""){ qCritical() << "Invalid folder specified."; return false; } QString split_text = ""; if(split_type == EXPORT_VAL){ split_text = "VAL"; progress.setWindowTitle("Exporting validation images"); }else if(split_type == EXPORT_TRAIN){ split_text = "TRAIN"; progress.setWindowTitle("Exporting train images"); }else if(split_type == EXPORT_TEST){ split_text = "TEST"; progress.setWindowTitle("Exporting test images"); }else{ split_text = "UNASSIGNED"; } if(!disable_progress){ progress.hide(); } int i = 0; int processed = 0; // Open shards QList shards; for(int s=0; s < number_shards; s++){ qInfo() << "Creating output shard files"; QString shard_name = QString("%1-%2-of-%3.tfrecord") .arg(record_prefix) .arg(s, 5, 10, static_cast('0')) .arg(number_shards, 5, 10, static_cast('0')); QString shard_path = QDir(output_folder).absoluteFilePath(shard_name); auto shard = new QFile(shard_path); if(shard->exists()){ shard->remove(); qWarning() << "Deleting and overwriting " << shard_path; } shard->open(QFile::Append); shards.push_back(shard); } foreach(image_path, images){ if(progress.wasCanceled()){ break; } project->getLabels(image_path, labels); tensorflow::Example example; bool res = create_example(example, image_path); if(res){ qDebug() << "creating record for " << image_path; int shard_id = processed++ % number_shards; auto serialised_example = example.SerializeAsString(); auto shard = shards.at(shard_id); if(shard->isOpen()){ // Write header (data length, crc of data length) size_t data_len = example.ByteSizeLong(); auto data_len_ptr = reinterpret_cast(&data_len); int nbytes = shard->write(data_len_ptr, 8); uint32_t crc32 = tf_crc::Mask(tf_crc::Value(data_len_ptr, 8)); shard->write(reinterpret_cast(&crc32), 4); // Write record nbytes += shard->write(serialised_example.data(), serialised_example.size()); // Write footer (CRC32 of data) crc32 = tf_crc::Mask(tf_crc::Value(serialised_example.data(), serialised_example.size())); shard->write(reinterpret_cast(&crc32), 4); if(nbytes <=0){ qCritical() << "Failed to write shard"; }else{ qDebug() << "Wrote " << nbytes << "bytes"; } }else{ qCritical() << "Shard is not open for writing"; } } if(!disable_progress){ progress.setValue(i++); progress.setLabelText(image_path); } } for(auto &shard : shards){ shard->close(); delete shard; } return true; } void TFRecordExporter::process(void){ create_weights(); processImages(train_folder, "train", train_set, EXPORT_TRAIN); processImages(val_folder, "val", validation_set, EXPORT_VAL); } ================================================ FILE: src/tfrecordexporter.h ================================================ #ifndef TFRECORDEXPORTER_H #define TFRECORDEXPORTER_H #include "baseexporter.h" #include #include #include #include class TFRecordExporter : public BaseExporter { public: explicit TFRecordExporter(LabelProject *project, QObject *parent = nullptr) : BaseExporter(project, parent){} void setNumberShards(int n); void generateLabelIds(const QString names_file); void process(void); private: bool create_example(tensorflow::Example &example, QString image_path); void add_int64_feature(tensorflow::Features &features, std::string key, std::vector values); void add_bytes_feature(tensorflow::Features &features, std::string key, std::vector values, std::vector size); void add_bytes_feature(tensorflow::Features &features, std::string key, std::vector values); void add_float_feature(tensorflow::Features &features, std::string key, std::vector values); QMap weight_map; void create_weights(); bool processImages(const QString folder, const QString record_prefix, const QList images, export_image_type split_type); int number_shards = 10; }; #endif // TFRECORDEXPORTER_H ================================================ FILE: src/tfrecordimporter.cpp ================================================ #include "tfrecordimporter.h" void TFRecordImporter::find_example_boundaries(QByteArray buffer, std::vector &record_offsets, std::vector &record_sizes){ size_t offset = 0; size_t next_offset = 0; size_t header_size = 12; size_t footer_size = 4; size_t buffer_size = static_cast(buffer.size()); while(offset < buffer_size){ QByteArray data_len_buf = buffer.mid(static_cast(offset), 8); QByteArray data_len_crc_buf = buffer.mid(static_cast(offset)+8, 4); size_t data_size = *reinterpret_cast(data_len_buf.data()); size_t data_len_crc = *reinterpret_cast(data_len_crc_buf.data()); uint32_t crc = tf_crc::Mask(tf_crc::Value(data_len_buf.data(), 8)); if(data_len_crc == crc){ // 4 to account for header and footer next_offset = offset + data_size + header_size + footer_size; record_offsets.push_back(offset + header_size); record_sizes.push_back(data_size + footer_size); qWarning() << "Found record at " << offset << " with size: " << data_size; }else{ qWarning() << "Incorrect CRC, corrupt file?"; break; } offset = next_offset; } } void TFRecordImporter::process_example(tensorflow::Example &example){ // Image metadata auto map = example.features().feature(); int image_height = map["image/height"].int64_list().value(0); int image_width = map["image/width"].int64_list().value(0); std::string image_filename = map["image/filename"].bytes_list().value(0); std::string source_id = map["image/source_id"].bytes_list().value(0); std::string ext = map["image/format"].bytes_list().value(0); std::string image_data = map["image/encoded"].bytes_list().value(0); cv::Mat cv_buffer = cv::Mat(1, static_cast(image_data.size()), CV_8UC1, const_cast(image_data.data())); qDebug() << "Performing image integrity check"; cv::Mat image = cv::imdecode(cv_buffer, cv::IMREAD_UNCHANGED); if(image_height != image.rows){ qWarning() << "Ignoring example: decoded image height does not match record height"; return; } if(image_width != image.cols){ qWarning() << "Ignoring record: decoded image height does not match record height"; return; } int n_boxes = map["image/object/bbox/xmin"].float_list().value_size(); qDebug() << "Image countains: " << n_boxes << " bounding boxes"; if(n_boxes == 0 && !import_unlabelled){ return; } project->addAsset(QString::fromStdString(image_filename)); for(int i=0; i < n_boxes; ++i){ auto xmin = map["image/object/bbox/xmin"].float_list().value(i); auto xmax = map["image/object/bbox/xmax"].float_list().value(i); auto ymin = map["image/object/bbox/ymin"].float_list().value(i); auto ymax = map["image/object/bbox/ymax"].float_list().value(i); auto class_name = map["image/object/class/text"].bytes_list().value(i); auto class_id = map["image/object/class/label"].int64_list().value(i); BoundingBox box; box.classid = class_id; box.classname = QString::fromStdString(class_name); box.rect = QRect(QPoint(xmin*image_width, ymin*image_height), QPoint(xmax*image_width, ymax*image_height)); qDebug() << printBoundingBox(box); project->addLabel(QString::fromStdString(image_filename), box); } } void TFRecordImporter::import_records(QString filename_mask){ QFileInfo filemask(filename_mask); auto dir_name = filemask.absoluteDir().absolutePath(); QDirIterator it(dir_name, {filemask.baseName()}, QDir::Files); QStringList record_files; while (it.hasNext()) { auto record = QDir(it.next()).canonicalPath(); record_files.append(record); qDebug() << "Found : " << record; } record_files.removeDuplicates(); record_files.sort(); for(auto &record : record_files){ import(record); } } void TFRecordImporter::import(QString filename){ qDebug() << "Processing record :" << filename; QFile f(filename); f.open(QIODevice::ReadOnly); auto buffer = f.readAll(); qDebug() << "File size:" << buffer.size(); std::vector record_offsets; std::vector record_sizes; find_example_boundaries(buffer, record_offsets, record_sizes); qDebug() << "Found : " << record_offsets.size() << " examples in file."; std::vector examples; for(size_t i=0; i < record_offsets.size(); i++){ int curr_offset = static_cast(record_offsets.at(i)); int record_length = static_cast(record_sizes.at(i)); QByteArray example_buffer = buffer.mid(curr_offset, record_length); tensorflow::Example example; example.ParseFromArray(example_buffer.data(), example_buffer.size()); process_example(example); } } ================================================ FILE: src/tfrecordimporter.h ================================================ #ifndef TFRECORDIMPORTER_H #define TFRECORDIMPORTER_H #include "baseimporter.h" #include #include #include #include class TFRecordImporter : public BaseImporter { public: using BaseImporter::import; explicit TFRecordImporter(LabelProject *project, QObject *parent = nullptr) : BaseImporter(parent){ this->project = project; } void import_records(QString filename_mask); void import(QString filename); private: void find_example_boundaries(QByteArray buffer, std::vector &record_offsets, std::vector &record_sizes); void process_example(tensorflow::Example &example); }; #endif // TFRECORDIMPORTER_H ================================================ FILE: src/videoexporter.cpp ================================================ #include "videoexporter.h" std::unordered_map VideoExporter::colour_hashmap{ { "Cividis", cv::COLORMAP_CIVIDIS }, { "Inferno", cv::COLORMAP_INFERNO }, { "Magma", cv::COLORMAP_MAGMA }, { "Hot", cv::COLORMAP_HOT }, { "Bone", cv::COLORMAP_BONE }, { "Plasma", cv::COLORMAP_PLASMA }, { "Jet", cv::COLORMAP_JET }, { "Rainbow", cv::COLORMAP_RAINBOW }, { "Ocean", cv::COLORMAP_OCEAN }, { "Viridis", cv::COLORMAP_VIRIDIS } }; void VideoExporter::process() { auto out_filename = QDir(output_folder).absoluteFilePath(filename); cv::VideoWriter writer(out_filename.toStdString(), fourcc, fps, frame_size); QList images; if(export_unlabelled) project->getImageList(images); else project->getLabelledImageList(images); if(!writer.isOpened()){ qCritical() << "Failed to open video writer"; } auto pbar = cliProgressBar(); double progress = 0; int i = 0; qInfo() << "Writing video to file:" << out_filename; for(auto &abs_image_path : images){ // Read auto image = cv::imread(abs_image_path.toStdString(), cv::IMREAD_UNCHANGED); int w, h; w = image.cols; h = image.rows; cv::Mat image_resized; cv::resize(image, image_resized, frame_size); if(image_resized.elemSize() == 2){ convert16(image_resized); } if (image_resized.channels() == 4){ cv::cvtColor(image_resized, image_resized, cv::COLOR_RGBA2RGB); }else if(image_resized.channels() == 1){ cv::applyColorMap(image_resized, image_resized, colourmap); } if(this->display_boxes){ QList labels; project->getLabels(abs_image_path, labels); for(auto &label : labels){ double x_scale = static_cast(w)/image_resized.cols; double y_scale = static_cast(h)/image_resized.rows; drawBoundingBox(image_resized, label, x_scale, y_scale, this->box_thickness); } } writer.write(image_resized); progress = 100*static_cast(i++)/images.size(); pbar.update(progress); pbar.print(); } writer.release(); } void VideoExporter::drawBoundingBox(cv::Mat &source, BoundingBox box, double x_scale, double y_scale, int thickness){ int top_x = box.rect.x()/x_scale; int top_y = box.rect.y()/y_scale; auto rect = cv::Rect2i(top_x, top_y, box.rect.width()/x_scale, box.rect.height()/y_scale); auto colour_list = QColor::colorNames(); QColor colour = QColor(colour_list.at(std::max(0, box.classid) % colour_list.size()) ); cv::Scalar color(colour.red(), colour.green(), colour.blue()); cv::rectangle(source, rect, color, thickness); if(display_names){ auto label_string = QString("%1").arg(box.classname).toStdString(); int baseline; auto text_size = cv::getTextSize(label_string, cv::FONT_HERSHEY_COMPLEX_SMALL, this->font_scale, thickness, &baseline); cv::Rect2i label_background(top_x, top_y-text_size.height-5, std::max(static_cast(box.rect.width()/x_scale), text_size.width), text_size.height+5); cv::rectangle(source, label_background, color, -1); auto text_colour = cv::Scalar(0,0,0); if(colour.red() == 0 && colour.green() == 0 && colour.blue() == 0){ text_colour = {255,255,255}; } cv::putText(source, label_string, {top_x, top_y-1}, cv::FONT_HERSHEY_COMPLEX_SMALL, this->font_scale, text_colour, thickness); } } void VideoExporter::convert16(cv::Mat &source, double minval, double maxval){ if(minval < 0 || maxval < 0){ cv::minMaxIdx(source, &minval, &maxval); } double range = maxval-minval; double scale_factor = 255.0/range; source.convertTo(source, CV_32FC1); source -= minval; source *= scale_factor; source.convertTo(source, CV_8UC1); return; } void VideoExporter::labelConfig(bool display_names, bool display_boxes, int box_thickness, double font_size){ this->display_names = display_names; this->display_boxes = display_boxes; this->box_thickness = box_thickness; this->font_scale = font_size; } void VideoExporter::videoConfig(QString filename, QString fourcc_string, double fps, cv::Size frame_size, QString colourmap) { this->filename = filename; this->fps = fps; this->fourcc = cv::VideoWriter::fourcc(fourcc_string.at(0).toLatin1(), fourcc_string.at(1).toLatin1(), fourcc_string.at(2).toLatin1(), fourcc_string.at(3).toLatin1()); this->frame_size = frame_size; this->colourmap = colour_hashmap[colourmap.toStdString()]; } ================================================ FILE: src/videoexporter.h ================================================ #ifndef VIDEOEXPORTER_H #define VIDEOEXPORTER_H #include "baseexporter.h" #include class VideoExporter : public BaseExporter { public: explicit VideoExporter(LabelProject *project, QObject *parent = nullptr) : BaseExporter(project, parent){} void videoConfig(QString filename, QString fourcc_string = "h264", double fps = 10, cv::Size frame_size = {1280,720}, QString colormap="Inferno"); void process(); void labelConfig(bool display_names=true, bool label_boxes=true, int box_thickness=1, double font_scale=1); private: QString filename; int fourcc; int colourmap; double fps = 10; cv::Size frame_size; bool display_names = true; bool display_boxes = true; bool box_thickness = 1; double font_scale = 0.8; void normalise(cv::Mat &image_raw, cv::Mat &image_norm); static std::unordered_map colour_hashmap; void convert16(cv::Mat &source, double minval = -1, double maxval = -1); void drawBoundingBox(cv::Mat &source, BoundingBox box, double x_scale, double y_scale, int thickness=1); }; #endif // VIDEOEXPORTER_H