├── .gitignore ├── LICENSE ├── Makefile ├── affine_transformations ├── Makefile ├── reflection2d.cpp ├── reflection2d_readme.md ├── reflection2d_test ├── reflection3d.cpp ├── reflection3d_readme.md ├── reflection3d_test ├── rotation2d.cpp ├── rotation2d_readme.md ├── rotation2d_test ├── rotation3d.cpp ├── rotation3d_readme.md ├── rotation3d_test ├── scaling2d.cpp ├── scaling2d_readme.md ├── scaling2d_test ├── scaling3d.cpp ├── scaling3d_readme.md ├── scaling3d_test ├── translation2d.cpp ├── translation2d_readme.md ├── translation2d_test ├── translation3d.cpp ├── translation3d_readme.md └── translation3d_test ├── audio_compression ├── Makefile ├── frequency_sensitivity.cpp ├── frequency_sensitivity_readme.md ├── frequency_sensitivity_test ├── masking.cpp ├── masking_readme.md └── masking_test ├── camera_models ├── Makefile ├── distortion.cpp ├── distortion_readme.md ├── distortion_test ├── extrinsics.cpp ├── extrinsics_readme.md ├── extrinsics_test ├── intrinsics.cpp ├── intrinsics_readme.md └── intrinsics_test ├── common ├── 3dutils │ ├── Makefile │ ├── confviz.cpp │ ├── confviz.hpp │ ├── vizwin.cpp │ └── vizwin.hpp ├── Makefile ├── appbase.mak ├── auxbase.mak ├── common.mak ├── comutils │ ├── Makefile │ ├── common.hpp │ ├── common.impl.hpp │ ├── coswave.hpp │ ├── coswave.impl.hpp │ ├── format.cpp │ ├── format.hpp │ ├── math.cpp │ ├── math.hpp │ ├── math.impl.hpp │ ├── mixer.hpp │ ├── mixer.impl.hpp │ ├── sinewave.hpp │ ├── sinewave.impl.hpp │ ├── wavegen.hpp │ └── wavegen.impl.hpp ├── imgutils │ ├── Makefile │ ├── colors.hpp │ ├── combine.cpp │ ├── combine.hpp │ ├── combine.impl.hpp │ ├── drawtext.cpp │ ├── drawtext.hpp │ ├── imgmath.cpp │ ├── imgmath.hpp │ ├── imgmath.impl.hpp │ ├── multiwin.cpp │ ├── multiwin.hpp │ ├── plot.cpp │ ├── plot.hpp │ ├── plot.impl.hpp │ ├── winctrl.cpp │ ├── winctrl.hpp │ ├── winctrl.impl.hpp │ ├── window.cpp │ └── window.hpp ├── sndutils │ ├── Makefile │ ├── player.hpp │ └── player.impl.hpp └── tools.mak ├── content-based_image_retrieval ├── Makefile ├── histogram.cpp ├── histogram_readme.md ├── histogram_test ├── mean_feature.cpp ├── mean_feature_readme.md ├── mean_feature_test ├── quantization.cpp ├── quantization_readme.md └── quantization_test ├── create_archive.sh ├── create_mini_archive.sh ├── demolist.md ├── features ├── Makefile ├── difference_of_gaussians.cpp ├── difference_of_gaussians_readme.md ├── difference_of_gaussians_test ├── gaussian.cpp ├── gaussian_readme.md ├── gaussian_test ├── matching_perspective.cpp ├── matching_perspective_readme.md ├── matching_perspective_test ├── panoramic_image.cpp ├── panoramic_image_readme.md ├── panoramic_image_test ├── sift_keypoint_matching.cpp ├── sift_keypoint_matching_readme.md ├── sift_keypoint_matching_test ├── sift_keypoints.cpp ├── sift_keypoints_readme.md └── sift_keypoints_test ├── frequency_transforms ├── Makefile ├── dct_composition.cpp ├── dct_composition_readme.md └── dct_composition_test ├── fundamentals_of_stereoscopy ├── Makefile ├── anaglyph.cpp ├── anaglyph_readme.md ├── anaglyph_test ├── epipolar_lines.cpp ├── epipolar_lines_readme.md └── epipolar_lines_test ├── global_todos.txt ├── image_compression ├── Makefile ├── chroma_subsampling.cpp ├── chroma_subsampling_readme.md ├── chroma_subsampling_test ├── csf.cpp ├── csf_readme.md ├── csf_test ├── dct_basis.cpp ├── dct_basis_readme.md ├── dct_basis_test ├── dct_decomposition.cpp ├── dct_decomposition_readme.md ├── dct_decomposition_test ├── jpeg_quality.cpp ├── jpeg_quality_readme.md ├── jpeg_quality_test ├── rgb_mixer.cpp ├── rgb_mixer_readme.md ├── rgb_mixer_test ├── rgb_vs_ycbcr.cpp ├── rgb_vs_ycbcr_readme.md ├── rgb_vs_ycbcr_test ├── ycbcr_mixer.cpp ├── ycbcr_mixer_readme.md └── ycbcr_mixer_test ├── object_detection ├── Makefile ├── haar_detection.cpp ├── haar_detection_readme.md ├── haar_detection_test ├── resampling.cpp ├── resampling_readme.md ├── resampling_test ├── viola_jones.cpp ├── viola_jones_readme.md └── viola_jones_test ├── opencv_config.md ├── readme.md ├── screenshots ├── anaglyph.png ├── checkerboard.png ├── chroma_subsampling.png ├── chroma_subsampling_444.png ├── csf.png ├── dct_basis.png ├── dct_composition.png ├── dct_composition_1.png ├── dct_decomposition.png ├── dct_decomposition_5_animated.png ├── dct_decomposition_5_during_animation.webp ├── difference_of_gaussians.png ├── difference_of_gaussians_k4.png ├── distortion.png ├── distortion_negative_p1_p2.png ├── epipolar_lines.png ├── epipolar_lines_eye.png ├── extrinsics.png ├── extrinsics_negative_z_translation.png ├── frequency_sensitivity.png ├── frequency_sensitivity_50_mute.png ├── gaussian.png ├── gaussian_sigma5.png ├── haar_detection.png ├── haar_detection_eyes.png ├── histogram.png ├── histogram_64_bins.png ├── homography.png ├── homography_after_warping.png ├── howto_animation.txt ├── intra_prediction.png ├── intra_prediction_horizontal.png ├── intrinsics.png ├── intrinsics_fx600_cx250.png ├── jpeg_quality.png ├── jpeg_quality_1.png ├── masking.png ├── masking_100_0_mute.png ├── matching_perspective.png ├── matching_perspective_tractor.png ├── mean_feature.png ├── mean_feature_zoomed.png ├── missing.txt ├── motion_estimation.png ├── motion_estimation_perform_costmap.png ├── panoramic_image.png ├── quantization.png ├── quantization_8.png ├── reconstruct3d.png ├── reconstruct3d_zoomed.png ├── reflection2d.png ├── reflection2d_90.png ├── reflection3d.png ├── reflection3d_xz.png ├── resampling.png ├── resampling_5pc_bilinear.png ├── rgb_mixer.png ├── rgb_mixer_yellow.png ├── rgb_vs_ycbcr.png ├── rotation2d.png ├── rotation2d_135.png ├── rotation3d.png ├── rotation3d_x180_y90.png ├── scaling2d.png ├── scaling2d_200.png ├── scaling3d.png ├── scaling3d_x50_y200.png ├── semiglobal_matching.png ├── sift_keypoint_matching.png ├── sift_keypoint_matching_point92.png ├── sift_keypoints.png ├── translation2d.png ├── translation2d_x20_y-30.png ├── translation3d.png ├── translation3d_x-10_z20.png ├── viola_jones.png ├── viola_jones_ice.png ├── ycbcr_mixer.png └── ycbcr_mixer_grey.png ├── stereo_matching ├── Makefile ├── checkerboard.cpp ├── checkerboard_readme.md ├── checkerboard_test ├── homography.cpp ├── homography_readme.md ├── homography_test ├── reconstruct3d.cpp ├── reconstruct3d_readme.md ├── reconstruct3d_test ├── semiglobal_matching.cpp ├── semiglobal_matching_readme.md └── semiglobal_matching_test ├── testdata ├── 3dmodels │ ├── bun_zipper.ply │ └── sources.txt └── images │ ├── 001.png │ ├── 002.png │ ├── Lenna.png │ ├── disp2.png │ ├── f001.png │ ├── f002.png │ ├── f003.png │ ├── f004.png │ ├── f005.png │ ├── f006.png │ ├── f007.png │ ├── f008.png │ ├── f009.png │ ├── f010.png │ ├── im2.png │ ├── im6.png │ ├── news.png │ ├── pan001.png │ ├── pan002.png │ ├── pan003.png │ ├── pan004.png │ ├── pan005.png │ ├── pan006.png │ ├── pan007.png │ ├── recttext.png │ ├── sources.txt │ ├── t001.png │ ├── t002.png │ ├── t003.png │ ├── t004.png │ ├── t005.png │ ├── t006.png │ ├── t007.png │ ├── t008.png │ ├── t009.png │ ├── t010.png │ ├── t011.png │ ├── t012.png │ ├── t013.png │ ├── t014.png │ └── tractor.png ├── todo.sh └── video_compression ├── Makefile ├── intra_prediction.cpp ├── intra_prediction_readme.md ├── intra_prediction_test ├── motion_estimation.cpp ├── motion_estimation_readme.md └── motion_estimation_test /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.o 3 | 4 | # Executables 5 | *.exe 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2018-2020, Andreas Unterweger (andreas-unterweger@andreas-unterweger.eu) 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #Makefile for all applications (subfolders) 2 | # Andreas Unterweger, 2016-2018 3 | #This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | include common/tools.mak 6 | 7 | ALLDIR := $(wildcard */) 8 | ALLDIR := $(ALLDIR:%/=%) 9 | 10 | DATADIR := screenshots testdata 11 | CODEDIR := $(filter-out $(DATADIR), $(ALLDIR)) 12 | COMMONDIR := common 13 | DIR := $(filter-out $(COMMONDIR), $(CODEDIR)) 14 | 15 | BUILDDIRCMD := $(addprefix build-, $(DIR)) 16 | CLEANDIRCMD := $(addprefix clean-, $(CODEDIR)) 17 | TSTDIRCMD := $(addprefix test-, $(DIR)) 18 | 19 | build-%: 20 | $(CD) $* && $(MAKE) 21 | 22 | clean-%: 23 | $(CD) $* && $(MAKE) clean 24 | 25 | .DEFAULT_GOAL := all 26 | 27 | all: $(BUILDDIRCMD) 28 | 29 | clean: $(CLEANDIRCMD) 30 | 31 | test-%: 32 | $(CD) $* && $(MAKE) tests 33 | 34 | tests: $(TSTDIRCMD) 35 | -------------------------------------------------------------------------------- /affine_transformations/Makefile: -------------------------------------------------------------------------------- 1 | PARTS = 3d 2 | 3 | ORDER := reflection2d reflection3d rotation2d rotation3d scaling2d scaling3d translation2d translation3d 4 | 5 | include ../common/appbase.mak 6 | -------------------------------------------------------------------------------- /affine_transformations/reflection2d_readme.md: -------------------------------------------------------------------------------- 1 | 2-D reflection 2 | ============== 3 | 4 | **Short description**: Illustration of 2-D reflection across a line (Illustrates reflection in two dimensions) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Complete 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/reflection2d.png) 14 | 15 | Reflecting a point (illustrated by an arrow in the *2-D reflection across a line* window) across a line is a building block for more complex affine coordinate transformations. Objects, e.g., a whole letter, can be reflected by reflecting all the points they consist of individually. 16 | 17 | Usage 18 | ----- 19 | 20 | Change the angle between the reflection line and the X axis (see parameters below) to see the position of the reflected letter A (white) change compared to the original letter's (semi-transparent). Observe that the distance between any point of the original letter and the reflection line is the same as the distance between the reflection line and the corresponding reflected point, given that the distances are measured orthogonal to the reflection line. 21 | 22 | ![Screenshot after reflecting across the Y axis](../screenshots/reflection2d_90.png) 23 | 24 | Available actions 25 | ----------------- 26 | 27 | None 28 | 29 | Interactive parameters 30 | ---------------------- 31 | 32 | * **Reflection line angle** (track bar in the *2-D reflection parameters* window): Allows changing the angle between the reflection line and the X axis between 0 and 180 degrees. 33 | 34 | Program parameters 35 | ------------------ 36 | 37 | None 38 | 39 | Hard-coded parameters 40 | --------------------- 41 | 42 | * `letter_size` (local to `reflection_data`): Width and height of the displayed letter in relative coordinates. 43 | * `text` (local to `reflection_data::AddObjects`): Letter(s) to be rendered. 44 | 45 | Known issues 46 | ------------ 47 | 48 | None 49 | 50 | Missing features 51 | ---------------- 52 | 53 | None 54 | 55 | License 56 | ------- 57 | 58 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. -------------------------------------------------------------------------------- /affine_transformations/reflection2d_test: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /affine_transformations/reflection3d_readme.md: -------------------------------------------------------------------------------- 1 | 3-D reflection 2 | ============== 3 | 4 | **Short description**: Illustration of 3-D reflection across a plane (Illustrates reflection in three dimensions) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Near-complete (nice-to-have features missing) 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/reflection3d.png) 14 | 15 | Reflecting a point (illustrated by an arrow in the *3-D reflection across a plane* window) across a plane is a building block for more complex affine coordinate transformations. Objects, e.g., a 3-D model, can be reflected by reflecting all the points they consist of individually. 16 | 17 | Usage 18 | ----- 19 | 20 | Change the reflection plane (see parameters below) to see the position of the reflected 3-D model (white) change compared to the original 3-D model (semi-transparent). Observe that the distance between any point of the original model and the reflection plane (yellow, semi-transparent) is the same as the distance between the reflection plane and the corresponding reflected point, given that the distances are measured orthogonal to the reflection plane. 21 | 22 | ![Screenshot after reflecting across the XZ plane](../screenshots/reflection3d_xz.png) 23 | 24 | Available actions 25 | ----------------- 26 | 27 | None 28 | 29 | Interactive parameters 30 | ---------------------- 31 | 32 | * **Reflection plane** (radio buttons): Allows switching between reflecting at the YZ plane, the XZ plane and the XY plane. 33 | 34 | Program parameters 35 | ------------------ 36 | 37 | None 38 | 39 | Hard-coded parameters 40 | --------------------- 41 | 42 | * `cone_length` (local to `scaling_data`): Height of the displayed cone in relative coordinates. 43 | * `cone_radius` (local to `scaling_data`): Radius of the displayed cone in relative coordinates. 44 | 45 | Known issues 46 | ------------ 47 | 48 | None 49 | 50 | Missing features 51 | ---------------- 52 | 53 | * **Automatic coordinate system size adjustment**: The size of the coordinate axes does not depend on the size of the loaded model, but on the hard-coded size of the cone. 54 | 55 | License 56 | ------- 57 | 58 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. -------------------------------------------------------------------------------- /affine_transformations/reflection3d_test: -------------------------------------------------------------------------------- 1 | ../testdata/3dmodels/bun_zipper.ply 2 | 3 | -------------------------------------------------------------------------------- /affine_transformations/rotation2d_readme.md: -------------------------------------------------------------------------------- 1 | 2-D rotation 2 | ============ 3 | 4 | **Short description**: Illustration of 2-D rotation around the origin (Illustrates rotation in two dimensions) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Complete 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/rotation2d.png) 14 | 15 | Rotating a point (illustrated by an arrow in the *2-D rotation around the origin* window) around the origin is a building block for more complex affine coordinate transformations. Objects, e.g., a whole letter, can be rotated by rotating all the points they consist of individually. 16 | 17 | Usage 18 | ----- 19 | 20 | Change the angle of rotation (see parameters below) to see the position of the rotated letter A (white) change compared to the original letter's (semi-transparent). Observe that the distance between each point of the letter and the origin of the coordinate system (where the red and blue lines meet) does not change. 21 | 22 | ![Screenshot after rotating the letter around the origin](../screenshots/rotation2d_135.png) 23 | 24 | Available actions 25 | ----------------- 26 | 27 | None 28 | 29 | Interactive parameters 30 | ---------------------- 31 | 32 | * **Angle** (track bar in the *2-D rotation parameters* window): Allows changing the angle of rotation between 0 and 360 degrees. 33 | 34 | Program parameters 35 | ------------------ 36 | 37 | None 38 | 39 | Hard-coded parameters 40 | --------------------- 41 | 42 | * `letter_size` (local to `rotation_data`): Width and height of the displayed letter in relative coordinates. 43 | * `text` (local to `rotation_data::AddObjects`): Letter(s) to be rendered. 44 | 45 | Known issues 46 | ------------ 47 | 48 | None 49 | 50 | Missing features 51 | ---------------- 52 | 53 | None 54 | 55 | License 56 | ------- 57 | 58 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. -------------------------------------------------------------------------------- /affine_transformations/rotation2d_test: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /affine_transformations/rotation3d_readme.md: -------------------------------------------------------------------------------- 1 | 3-D rotation 2 | ============ 3 | 4 | **Short description**: Illustration of 3-D rotation around an axis (Illustrates rotation in three dimensions) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Near-complete (nice-to-have features missing) 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/rotation3d.png) 14 | 15 | Rotating a point or collection of points around one of the coordinate axes is a building block for more complex affine coordinate transformations. Objects, e.g., a 3-D model of a bunny (*3-D rotation* window), can be rotated by rotating all the points they consist of individually. 16 | 17 | Usage 18 | ----- 19 | 20 | Change the angle of rotation around one axis (see parameters below) to see the position of the rotated bunny (white) change compared to the original's (semi-transparent). Observe that the distance between each point of the bunny and the axis of rotation does not change. Rotating around one axis and then another is equivalent to performing one (more complex) affine transformation which is composed of the two individual rotations. 21 | 22 | ![Screenshot after rotating the bunny around the X and Y axes](../screenshots/rotation3d_x180_y90.png) 23 | 24 | Available actions 25 | ----------------- 26 | 27 | None 28 | 29 | Interactive parameters 30 | ---------------------- 31 | 32 | * **X angle** (track bar in the *3-D rotation parameters* window): Allows changing the angle of rotation around the X axis (red) between 0 and 360 degrees. 33 | * **Y angle** (track bar in the *3-D rotation parameters* window): Allows changing the angle of rotation around the Y axis (green) between 0 and 360 degrees. 34 | * **Z angle** (track bar in the *3-D rotation parameters* window): Allows changing the angle of rotation around the Z axis (blue) between 0 and 360 degrees. 35 | 36 | Program parameters 37 | ------------------ 38 | 39 | * **3-D model** (optional): File path of the PLY model to be rotated. If no path is specified, a 3-D cone (see parameters below) will be created instead. 40 | 41 | Hard-coded parameters 42 | --------------------- 43 | 44 | * `cone_length` (local to `rotation_data`): Height of the displayed cone in relative coordinates. 45 | * `cone_radius` (local to `rotation_data`): Radius of the displayed cone in relative coordinates. 46 | 47 | Known issues 48 | ------------ 49 | 50 | None 51 | 52 | Missing features 53 | ---------------- 54 | 55 | * **Automatic coordinate system size adjustment**: The size of the coordinate axes does not depend on the size of the loaded model, but on the hard-coded size of the cone. 56 | 57 | License 58 | ------- 59 | 60 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. -------------------------------------------------------------------------------- /affine_transformations/rotation3d_test: -------------------------------------------------------------------------------- 1 | ../testdata/3dmodels/bun_zipper.ply 2 | 3 | -------------------------------------------------------------------------------- /affine_transformations/scaling2d_readme.md: -------------------------------------------------------------------------------- 1 | 2-D scaling 2 | =========== 3 | 4 | **Short description**: Illustration of 2-D scaling (Illustrates scaling in two dimensions) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Complete 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/scaling2d.png) 14 | 15 | Scaling a point by multiplying its coordinates by a factor is one of the simplest affine coordinate transformations. Objects, e.g., a whole letter (window *2-D scaling*), can be scaled by scaling all the points they consist of individually. 16 | 17 | Usage 18 | ----- 19 | 20 | Change the zoom value (see parameters below) to see the position and size of the scaled letter A (white) change compared to the original letter's (semi-transparent). Observe that the distance between each point of the letter and the origin of the coordinate system (where the red and green lines meet) becomes a multiple of its original distance. The relative change is expressed by the zoom value. Using identical zoom values for both coordinates (X and Y) is referred to as isotropic scaling, which preserves the relative proportions of the letter. In contrast, using different zoom values for each coordinate is referred to as anisotropic scaling, which changes the aspect ratio, i.e., squeezes the letter. 21 | 22 | ![Screenshot after scaling the letter isotropically](../screenshots/scaling2d_200.png) 23 | 24 | Available actions 25 | ----------------- 26 | 27 | None 28 | 29 | Interactive parameters 30 | ---------------------- 31 | 32 | * **X zoom** (track bar in the *2-D scaling parameters* window): Allows changing the scaling factor for the X coordinate between 0 and 200%. 33 | * **Y zoom** (track bar in the *2-D scaling parameters* window): Allows changing the scaling factor for the Y coordinate between 0 and 200%. 34 | 35 | Program parameters 36 | ------------------ 37 | 38 | None 39 | 40 | Hard-coded parameters 41 | --------------------- 42 | 43 | * `letter_size` (local to `scaling_data`): Width and height of the displayed letter in relative coordinates. 44 | * `text` (local to `scaling_data::AddObjects`): Letter(s) to be rendered. 45 | 46 | Known issues 47 | ------------ 48 | 49 | None 50 | 51 | Missing features 52 | ---------------- 53 | 54 | None 55 | 56 | License 57 | ------- 58 | 59 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. -------------------------------------------------------------------------------- /affine_transformations/scaling2d_test: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /affine_transformations/scaling3d_readme.md: -------------------------------------------------------------------------------- 1 | 3-D scaling 2 | =========== 3 | 4 | **Short description**: Illustration of 3-D scaling (Illustrates scaling in three dimensions) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Near-complete (nice-to-have features missing) 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/scaling3d.png) 14 | 15 | Scaling a point by multiplying its coordinates by a factor is one of the simplest affine coordinate transformations. Objects, e.g., a 3-D model of a bunny (window *3-D scaling*), can be scaled by scaling all the points they consist of individually. 16 | 17 | Usage 18 | ----- 19 | 20 | Change the zoom value (see parameters below) to see the position and size of the scaled bunny (white) change compared to the original's (semi-transparent). Observe that the distance between each point of the bunny and the origin of the coordinate system (where the red and green lines meet) becomes a multiple of its original distance. The relative change is expressed by the zoom value. Using identical zoom values for all three coordinates (X, Y and Z) is referred to as isotropic scaling, which preserves the relative proportions of the bunny. In contrast, using different zoom values for each coordinate is referred to as anisotropic scaling, which changes the aspect ratio, i.e., squeezes the bunny. 21 | 22 | ![Screenshot after scaling the bunny anisotropically](../screenshots/scaling3d_x50_y200.png) 23 | 24 | Available actions 25 | ----------------- 26 | 27 | None 28 | 29 | Interactive parameters 30 | ---------------------- 31 | 32 | * **X zoom** (track bar in the *3-D scaling parameters* window): Allows changing scaling factor for the X coordinate between 0 and 200%. 33 | * **Y zoom** (track bar in the *3-D scaling parameters* window): Allows changing scaling factor for the Y coordinate between 0 and 200%. 34 | * **Z zoom** (track bar in the *3-D scaling parameters* window): Allows changing scaling factor for the Z coordinate between 0 and 200%. 35 | 36 | Program parameters 37 | ------------------ 38 | 39 | * **3-D model** (optional): File path of the PLY model to be scaled. If no path is specified, a 3-D cone (see parameters below) will be created instead. 40 | 41 | Hard-coded parameters 42 | --------------------- 43 | 44 | * `cone_length` (local to `scaling_data`): Height of the displayed cone in relative coordinates. 45 | * `cone_radius` (local to `scaling_data`): Radius of the displayed cone in relative coordinates. 46 | 47 | Known issues 48 | ------------ 49 | 50 | None 51 | 52 | Missing features 53 | ---------------- 54 | 55 | * **Automatic coordinate system size adjustment**: The size of the coordinate axes does not depend on the size of the loaded model, but on the hard-coded size of the cone. 56 | 57 | License 58 | ------- 59 | 60 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. -------------------------------------------------------------------------------- /affine_transformations/scaling3d_test: -------------------------------------------------------------------------------- 1 | ../testdata/3dmodels/bun_zipper.ply 2 | 3 | -------------------------------------------------------------------------------- /affine_transformations/translation2d_readme.md: -------------------------------------------------------------------------------- 1 | 2-D translation 2 | =============== 3 | 4 | **Short description**: Illustration of 2-D translation (Illustrates translation in two dimensions) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Complete 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/translation2d.png) 14 | 15 | Moving a point through translation is the only elementary affine tranformation which requires homogeneous coordinates. Objects, e.g., a whole letter (window *2-D translation*), can be moved by moving all the points they consist of individually. 16 | 17 | Usage 18 | ----- 19 | 20 | Change the offset (see parameters below) to see the position of the letter A (white) change compared to the original letter's (semi-transparent). Observe that the distance by which the letter is moved is absolute, i.e., it does not depend on the original position of the letter. The X and Y offsets can be changed independently of one another. 21 | 22 | ![Screenshot after moving the letter](../screenshots/translation2d_x20_y-30.png) 23 | 24 | Available actions 25 | ----------------- 26 | 27 | None 28 | 29 | Interactive parameters 30 | ---------------------- 31 | 32 | * **X offset** (track bar in the *2-D translation parameters* window): Allows changing the translation parameter along the X direction between -50 and 50 in relative coordinates. 33 | * **Y offset** (track bar in the *2-D translation parameters* window): Allows changing the translation parameter along the Y direction between -50 and 50 in relative coordinates. 34 | 35 | Program parameters 36 | ------------------ 37 | 38 | None 39 | 40 | Hard-coded parameters 41 | --------------------- 42 | 43 | * `letter_size` (local to `translation_data`): Width and height of the displayed letter in relative coordinates. 44 | * `text` (local to `translation_data::AddObjects`): Letter(s) to be rendered. 45 | 46 | Known issues 47 | ------------ 48 | 49 | None 50 | 51 | Missing features 52 | ---------------- 53 | 54 | None 55 | 56 | License 57 | ------- 58 | 59 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. -------------------------------------------------------------------------------- /affine_transformations/translation2d_test: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /affine_transformations/translation3d_readme.md: -------------------------------------------------------------------------------- 1 | 3-D translation 2 | =============== 3 | 4 | **Short description**: Illustration of 3-D translation (Illustrates translation in three dimensions) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Near-complete (nice-to-have features missing) 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/translation3d.png) 14 | 15 | Moving a point through translation is the only affine tranformation which requires homogeneous coordinates. Objects, e.g., a 3-D model of a bunny (window *3-D translation*), can be moved by moving all the points they consist of individually. 16 | 17 | Usage 18 | ----- 19 | 20 | Change the offset (see parameters below) to see the position of the bunny (white) change compared to the original's (semi-transparent). Observe that the distance by which the bunny is moved is absolute, i.e., it does not depend on the original position of the bunny. The X, Y and Z offsets can be changed independently of one another. 21 | 22 | ![Screenshot after moving the bunny](../screenshots/translation3d_x-10_z20.png) 23 | 24 | Available actions 25 | ----------------- 26 | 27 | None 28 | 29 | Interactive parameters 30 | ---------------------- 31 | 32 | * **X offset** (track bar in the *3-D translation parameters* window): Allows changing the translation parameter along the X direction between -50 and 50 in relative coordinates. 33 | * **Y offset** (track bar in the *3-D translation parameters* window): Allows changing the translation parameter along the Y direction between -50 and 50 in relative coordinates. 34 | * **Z offset** (track bar in the *3-D translation parameters* window): Allows changing the translation parameter along the Z direction between -50 and 50 in relative coordinates. 35 | 36 | Program parameters 37 | ------------------ 38 | 39 | * **3-D model** (optional): File path of the PLY model to be moved. If no path is specified, a 3-D cone (see parameters below) will be created instead. 40 | 41 | Hard-coded parameters 42 | --------------------- 43 | 44 | * `cone_length` (local to `translation_data`): Height of the displayed cone in relative coordinates. 45 | * `cone_radius` (local to `translation_data`): Radius of the displayed cone in relative coordinates. 46 | 47 | Known issues 48 | ------------ 49 | 50 | None 51 | 52 | Missing features 53 | ---------------- 54 | 55 | * **Automatic coordinate system size adjustment**: The size of the coordinate axes does not depend on the size of the loaded model, but on the hard-coded size of the cone. 56 | 57 | License 58 | ------- 59 | 60 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. -------------------------------------------------------------------------------- /affine_transformations/translation3d_test: -------------------------------------------------------------------------------- 1 | ../testdata/3dmodels/bun_zipper.ply 2 | 3 | -------------------------------------------------------------------------------- /audio_compression/Makefile: -------------------------------------------------------------------------------- 1 | PARTS = sound 2 | 3 | ORDER := frequency_sensitivity masking 4 | 5 | include ../common/appbase.mak 6 | -------------------------------------------------------------------------------- /audio_compression/frequency_sensitivity_readme.md: -------------------------------------------------------------------------------- 1 | Frequency sensitivity 2 | ===================== 3 | 4 | **Short description**: Illustration of frequency-dependent intensity sensitivity (Illustrates how intensities are perceived differently at different frequencies) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Complete 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/frequency_sensitivity.png) 14 | 15 | The sensitivity of humans to acoustic signals depends on the signal frequency, i.e., equally intense sinusodial tones (in terms of sound pressure) are not perceived as equally loud when they differ in frequency. Thus, the loudness of a signal is not reflected in a visualization of the signal intensity over time (blue line in the *Attenuation* window). 16 | 17 | Usage 18 | ----- 19 | 20 | Change the frequency (see parameters below) of the tone to hear the perceived loudness change despite the sound level remaining constant. Similarly, observe that a sound level which is barely audible for one frequency might is either clearly noteable or appear mute for another. This can be double-checked by actually muting the signal. 21 | 22 | ![Screenshot after changing the frequency and muting the signal](../screenshots/frequency_sensitivity_50_mute.png) 23 | 24 | Available actions 25 | ----------------- 26 | 27 | None 28 | 29 | Interactive parameters 30 | ---------------------- 31 | 32 | * **Frequency** (track bar in the *Attenuation* window): Allows changing the frequency of the sinusodial tone that is played back. 33 | * **Level** (track bar in the *Attenuation* window): Allows changing the intensity (amplitude) of the sinusodial tone that is played back. The intensitiy is specified as a level in (negative) decibel. 34 | * **Mute** (check box): Allows stopping and resuming playback, when unchecked and checked, respectively. 35 | 36 | Program parameters 37 | ------------------ 38 | 39 | None 40 | 41 | Hard-coded parameters 42 | --------------------- 43 | 44 | * `default_frequency` (local to `audio_data`): Initial signal frequency in Hertz when the program is started. *Note: This frequency must be smaller than or equal to `max_frequency`.* 45 | * `max_frequency` (local to `audio_data`): Maximum frequency in Hertz allowed to be configured for playback. *Note: The actual maximum frequency may be limited by the sound card, the driver and/or the speakers.* 46 | * `default_level` (local to `audio_data`): Initial amplitude of the sinusodial tone in decibel when the program is started. *Note: This amplitude must be smaller than or equal to `max_level`.* 47 | * `max_level` (local to `audio_data`): Maximum amplitude of the sinusodial tone in decibel allowed to be configured for playback. *Note: The actual maximum frequency is limited by the specified `audio_type` (see below).* 48 | * `audio_type` (local to `audio_data`): Data type used for audio samples during generation and playback. 8-bit, 16-bit and 32-bit data types are supported. 49 | 50 | Known issues 51 | ------------ 52 | 53 | None. 54 | 55 | Missing features 56 | ---------------- 57 | 58 | None 59 | 60 | License 61 | ------- 62 | 63 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. 64 | -------------------------------------------------------------------------------- /audio_compression/frequency_sensitivity_test: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /audio_compression/masking_test: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /camera_models/Makefile: -------------------------------------------------------------------------------- 1 | PARTS = 3d 2 | 3 | ORDER := intrinsics extrinsics distortion 4 | 5 | include ../common/appbase.mak 6 | -------------------------------------------------------------------------------- /camera_models/distortion_readme.md: -------------------------------------------------------------------------------- 1 | Non-linear distortion 2 | ===================== 3 | 4 | **Short description**: Illustration of non-linear lense distortion (Illustrates the effect of the distortion vector on a camera image) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Complete 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/distortion.png) 14 | 15 | Camera lenses cause non-linear distortions in the captured image. Comparing such a distorted image (right part of the *Undistorted vs. distorted* window) with that of an ideal pinhole camera (left) makes the distortions visible. For simplicity, distortions are often modeled as [polynomials with distortion coefficients](https://docs.opencv.org/4.6.0/d9/d0c/group__calib3d.html) to describe radial and tangential distortions. 16 | 17 | Usage 18 | ----- 19 | 20 | Change the distortion coefficients (see parameters below) to see the distorted image change. Observe that negative distortion coefficients change the type of distortion. 21 | 22 | ![Screenshot after setting negative p1 and p2 coefficients](../screenshots/distortion_negative_p1_p2.png) 23 | 24 | Available actions 25 | ----------------- 26 | 27 | * **Reset** (button): Sets all coefficients to zero (0). 28 | 29 | Interactive parameters 30 | ---------------------- 31 | 32 | * **k1*10^(-7)** (track bar in the *Undistorted vs. distorted* window): Allows changing the quadratic radial distortion coefficient between -100 and 100 with a scaling factor of 10^(-7). 33 | * **k2*10^(-10)** (track bar in the *Undistorted vs. distorted* window): Allows changing the quartic (bi-quadratic) radial distortion coefficient between -100 and 100 with a scaling factor of 10^(-10). 34 | * **p1*10^(-5)** (track bar in the *Undistorted vs. distorted* window): Allows changing the quadratic tangential distortion coefficient between -100 and 100 with a scaling factor of 10^(-5). 35 | * **p2*10^(-5)** (track bar in the *Undistorted vs. distorted* window): Allows changing the linear tangential distortion coefficient between -100 and 100 with a scaling factor of 10^(-5). 36 | 37 | Program parameters 38 | ------------------ 39 | 40 | * **Input image**: File path of the image to be distorted. 41 | 42 | Hard-coded parameters 43 | --------------------- 44 | 45 | * `max_negative_value` (local to `distortion_data::AddControls`): Absolute value of the minimum coefficient value that can be set via the trackbars 46 | * `max_positive_value` (local to `distortion_data::AddControls`): The maximum coefficient value that can be set via the trackbars 47 | 48 | *Note: The scaling factors for the coefficients are hard-coded, but the range of meaningful values is very limited. Thus, it is not recommended to change the scaling factors explicitly.* 49 | 50 | Known issues 51 | ------------ 52 | 53 | * **Use of `undistort`**: The `undistort` function is used instead of a `distort` function to calculate the distorted image, potentially showing incorrect results. However, the current implementation illustrates the basic effect of the parameters well enough in principle. 54 | 55 | Missing features 56 | ---------------- 57 | 58 | None 59 | 60 | License 61 | ------- 62 | 63 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. 64 | -------------------------------------------------------------------------------- /camera_models/distortion_test: -------------------------------------------------------------------------------- 1 | ../testdata/images/news.png 2 | -------------------------------------------------------------------------------- /camera_models/extrinsics_test: -------------------------------------------------------------------------------- 1 | ../testdata/3dmodels/bun_zipper.ply 2 | 3 | -------------------------------------------------------------------------------- /camera_models/intrinsics_readme.md: -------------------------------------------------------------------------------- 1 | Pinhole camera intrinsics 2 | ========================= 3 | 4 | **Short description**: Illustration of intrinsic camera parameters (Illustrates the effect of the intrinsic parameters of a pinhole camera) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Work in progress (features missing and external bugs unfixed) 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/intrinsics.png) 14 | 15 | The intrinsic parameters of a pinhole camera impact the image that it captures (window *Camera view*). The two main parameters are the focal length and the principal point. Both are two-dimensional and can be [expressed in pixels](https://docs.opencv.org/4.6.0/d9/d0c/group__calib3d.html). 16 | 17 | Usage 18 | ----- 19 | 20 | Change the coordinates of the image center (see parameters below) to see the position of the cone on the projection change. Observe that changing the focal length changes the size of the projected cone. When the X and Y focal lengths differ from one another, non-square sensor pixels are simulated and the projected cone's aspect ratio changes. 21 | 22 | ![Screenshot after changing the (y) focal length and the x image center](../screenshots/intrinsics_fx600_cx250.png) 23 | 24 | Available actions 25 | ----------------- 26 | 27 | None 28 | 29 | Interactive parameters 30 | ---------------------- 31 | 32 | * **Focal length (x)** (track bar in the *Intrinsic camera parameters* window): Allows changing the focal length in pixels along the X direction. 33 | * **Focal length (y)** (track bar in the *Intrinsic camera parameters* window): Allows changing the focal length in pixels along the Y direction. 34 | * **Image center (x)** (track bar in the *Intrinsic camera parameters* window): Allows changing the X coordinate of the image center in pixels. 35 | * **Image center (y)** (track bar in the *Intrinsic camera parameters* window): Allows changing the Y coordinate of the image center in pixels. 36 | 37 | Program parameters 38 | ------------------ 39 | 40 | * **3-D model** (optional): File path of the PLY model to be displayed. If no path is specified, a 3-D cone (see parameters below) will be created instead. 41 | 42 | Hard-coded parameters 43 | --------------------- 44 | 45 | * `cone_length` (local to `intrisics_data::AddObjects`): Height of the displayed cone in relative coordinates. 46 | * `cone_radius` (local to `intrisics_data::AddObjects`): Radius of the displayed cone in relative coordinates. 47 | 48 | Known issues 49 | ------------ 50 | 51 | * **Camera stuttering** (*OpenCV* bug): The camera stutters (and eventually shows nothing at all) when changing between parameter values (see [*OpenCV* issue #9388](https://github.com/opencv/opencv/issues/9388)). 52 | 53 | Missing features 54 | ---------------- 55 | 56 | * **No meaningful maximum value for focal lengths**: The maximum displayed X and Y focal lengths are arbitrary. 57 | 58 | License 59 | ------- 60 | 61 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. 62 | -------------------------------------------------------------------------------- /camera_models/intrinsics_test: -------------------------------------------------------------------------------- 1 | ../testdata/3dmodels/bun_zipper.ply 2 | 3 | -------------------------------------------------------------------------------- /common/3dutils/Makefile: -------------------------------------------------------------------------------- 1 | include ../auxbase.mak 2 | -------------------------------------------------------------------------------- /common/3dutils/confviz.cpp: -------------------------------------------------------------------------------- 1 | //Configurable visualization window abstraction 2 | // Andreas Unterweger, 2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #include "confviz.hpp" 6 | 7 | namespace vizutils 8 | { 9 | ConfigurableVisualizationWindow::ConfigurableVisualizationWindow(const std::string &visualization_window_title, const std::string &configuration_window_title, const imgutils::WindowAlignment alignment) 10 | : MultiWindow(alignment), 11 | visualization_window(visualization_window_title), 12 | configuration_window(configuration_window_title) 13 | { 14 | const cv::Size default_size(VisualizationWindow::default_window_width, VisualizationWindow::default_window_height); 15 | SetSize(default_size); 16 | SetWindows({&visualization_window, &configuration_window}); 17 | } 18 | 19 | void ConfigurableVisualizationWindow::SetSize(const cv::Size &size) 20 | { 21 | visualization_window.SetSize(size); 22 | const cv::Mat dummy_content(1, size.width, CV_8UC1, cv::Scalar(0)); //TODO: Find a better way than an "empty" image to show window controls 23 | configuration_window.UpdateContent(dummy_content); 24 | Update(); //Update positions 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /common/3dutils/confviz.hpp: -------------------------------------------------------------------------------- 1 | //Configurable visualization window abstraction (header) 2 | // Andreas Unterweger, 2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #include "window.hpp" 15 | #include "vizwin.hpp" 16 | #include "multiwin.hpp" 17 | 18 | namespace vizutils 19 | { 20 | //Represents a configurable visualization window, consisting of a visualization window and a configuration-only window with window controls 21 | class ConfigurableVisualizationWindow : public imgutils::MultiWindow 22 | { 23 | public: 24 | //Creates a new window with the given window (part) titles and alignment 25 | ConfigurableVisualizationWindow(const std::string &visualization_window_title, const std::string &configuration_window_title, const imgutils::WindowAlignment alignment = imgutils::WindowAlignment::Vertical); 26 | 27 | //The visualization window (part) 28 | VisualizationWindow visualization_window; 29 | //The configuration window (part) 30 | imgutils::Window configuration_window; 31 | 32 | //Sets the width and height of the visualization window as well as the width of the configuration window 33 | void SetSize(const cv::Size &size) override; 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /common/Makefile: -------------------------------------------------------------------------------- 1 | #Special Makefile for commonly used code (only used for cleaning and building on demand) 2 | # Andreas Unterweger, 2016-2018 3 | #This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | include tools.mak 6 | 7 | ALLDIR := $(wildcard */) 8 | ALLDIR := $(ALLDIR:%/=%) 9 | 10 | CLEANDIRCMD := $(addprefix clean-, $(ALLDIR)) 11 | 12 | .DEFAULT_GOAL := all 13 | 14 | all: 15 | @echo "Common files are built implicitly on demand. They can only be cleaned with this Makefile." 16 | 17 | clean-%: 18 | $(CD) $* && $(MAKE) clean 19 | 20 | clean: $(CLEANDIRCMD) 21 | -------------------------------------------------------------------------------- /common/appbase.mak: -------------------------------------------------------------------------------- 1 | #Base Makefile for all folders with applications (source code plus executables) 2 | # Andreas Unterweger, 2018-2022 3 | #This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #The directory that this file is contained in ($(CURDIR) does not change on include) 6 | CURRENTPATH := $(dir $(lastword $(MAKEFILE_LIST))) 7 | 8 | include $(CURRENTPATH)common.mak 9 | 10 | #Keep intermediate object files to allow for parallel builds (make removes them otherwise) 11 | .PRECIOUS: %.o 12 | 13 | EXE := $(OBJ:.o=.exe) 14 | TST := $(addprefix test_, $(EXE:.exe=)) 15 | 16 | %.exe: %.o $(OBJDEP) 17 | $(CXX) $^ -o $@ $(LDFLAGS) 18 | 19 | $(TST): test_%: %.exe %_test 20 | @while read test; \ 21 | do \ 22 | $(ECHO) ./$< $$test; \ 23 | ./$< $$test; \ 24 | done < $*_test 25 | 26 | .PHONY: $(TST) tests ordered_tests all clean 27 | 28 | tests: $(TST) 29 | 30 | ORDERED_TESTS := $(addprefix test_, $(ORDER)) 31 | 32 | COUNT_ORDERED_TESTS := $(words $(ORDERED_TESTS)) 33 | COUNT_TESTS := $(words $(TST)) 34 | ifneq ($(COUNT_ORDERED_TESTS), $(COUNT_TESTS)) 35 | $(warning Demonstrations may be missing when using the ordered_tests target.) 36 | $(warning $(COUNT_ORDERED_TESTS) ordered vs. $(COUNT_TESTS) available demonstrations.) 37 | endif 38 | 39 | ordered_tests: $(ORDERED_TESTS) 40 | 41 | .DEFAULT_GOAL := all 42 | 43 | all: $(EXE) 44 | 45 | clean:: 46 | $(RM) $(EXE) 47 | -------------------------------------------------------------------------------- /common/auxbase.mak: -------------------------------------------------------------------------------- 1 | #Base Makefile for all common folders (source code only) 2 | # Andreas Unterweger, 2018 3 | #This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #The directory that this file is contained in ($(CURDIR) does not change on include) 6 | CURRENTPATH := $(dir $(lastword $(MAKEFILE_LIST))) 7 | 8 | include $(CURRENTPATH)common.mak 9 | 10 | .DEFAULT_GOAL := all 11 | 12 | all: $(OBJ) 13 | -------------------------------------------------------------------------------- /common/common.mak: -------------------------------------------------------------------------------- 1 | #Common base for all Makefiles 2 | # Andreas Unterweger, 2016-2023 3 | #This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #The directory that this file is contained in ($(CURDIR) does not change on include) 6 | COMMONPATH := $(dir $(lastword $(MAKEFILE_LIST))) 7 | 8 | include $(COMMONPATH)/tools.mak 9 | 10 | DEBUG ?= 1 11 | 12 | CXXFLAGS += -c -std=c++17 13 | ifeq ($(DEBUG), 1) 14 | CXXFLAGS += -g -Wall -Wextra -Werror 15 | #CXXFLAGS += -Wpedantic #Uncomment once OpenCV's stitching header does not cause warnings/errors anymore 16 | else 17 | CXXFLAGS += -O3 -flto -march=native -mtune=native 18 | endif 19 | 20 | LDFLAGS += -pthread 21 | ifneq ($(DEBUG), 1) 22 | LDFLAGS += -O3 -flto 23 | endif 24 | 25 | SRCDEPS := comutils imgutils 26 | LIBS += opencv4 27 | ifneq ($(filter sound,$(PARTS)),) 28 | SRCDEPS += sndutils 29 | LIBS += ao 30 | endif 31 | ifneq ($(filter 3d,$(PARTS)),) 32 | SRCDEPS += 3dutils 33 | endif 34 | SRCDEPS := $(addprefix $(COMMONPATH)/, $(SRCDEPS)) 35 | CXXFLAGS += $(addprefix -I, $(SRCDEPS)) 36 | SRCDEP := $(wildcard $(addsuffix /*.cpp, $(SRCDEPS))) 37 | OBJDEP := $(SRCDEP:.cpp=.o) 38 | 39 | ifneq ($(LIBS),) 40 | CXXFLAGS += `$(PKGCFG) --cflags $(LIBS)` 41 | endif 42 | 43 | ifneq ($(LIBS),) 44 | LDFLAGS += `$(PKGCFG) --libs $(LIBS)` 45 | endif 46 | 47 | SRC := $(wildcard *.cpp) 48 | OBJ := $(SRC:.cpp=.o) 49 | 50 | %.o: %.cpp 51 | $(CXX) $< -o $@ $(CXXFLAGS) 52 | 53 | clean:: 54 | $(RM) $(OBJ) 55 | -------------------------------------------------------------------------------- /common/comutils/Makefile: -------------------------------------------------------------------------------- 1 | include ../auxbase.mak 2 | -------------------------------------------------------------------------------- /common/comutils/common.hpp: -------------------------------------------------------------------------------- 1 | //Commonly used functions (header) 2 | // Andreas Unterweger, 2016-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | namespace comutils 10 | { 11 | //Determines the number of elements of the given array 12 | template 13 | constexpr size_t arraysize(const T (&)[N]); 14 | } 15 | 16 | #include "common.impl.hpp" 17 | -------------------------------------------------------------------------------- /common/comutils/common.impl.hpp: -------------------------------------------------------------------------------- 1 | //Commonly used functions (template implementation) 2 | // Andreas Unterweger, 2016-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | //#include "common.hpp" 6 | 7 | namespace comutils 8 | { 9 | template 10 | constexpr size_t arraysize(const T (&)[N]) 11 | { 12 | return N; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /common/comutils/coswave.hpp: -------------------------------------------------------------------------------- 1 | //Cosine wave generator class (header) 2 | // Andreas Unterweger, 2017-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #pragma once 6 | 7 | #include "sinewave.hpp" 8 | 9 | namespace comutils 10 | { 11 | //Defines a generator for cosinusodial wave forms 12 | template 13 | class CosineWaveGenerator : public SineWaveGenerator 14 | { 15 | public: 16 | //Constructs a new instance of CosineWaveGenerator with the given channel parameters. If absolute_amplitude is true, amplitude is used as is. If it is false, amplitude is used relative to the value range of T. 17 | CosineWaveGenerator(const double frequency, const double amplitude = 1.0, const bool absolute_amplitude = false, const double initial_phase = 0, const unsigned int sampling_rate = 48000); 18 | 19 | //Returns the initial phase of the cosine wave 20 | virtual double GetInitialPhase() const; 21 | }; 22 | } 23 | 24 | #include "coswave.impl.hpp" 25 | -------------------------------------------------------------------------------- /common/comutils/coswave.impl.hpp: -------------------------------------------------------------------------------- 1 | //Cosine wave generator class (template implementation) 2 | // Andreas Unterweger, 2017-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #include 6 | 7 | //#include "coswave.hpp" 8 | 9 | namespace comutils 10 | { 11 | template 12 | CosineWaveGenerator::CosineWaveGenerator(const double frequency, const double amplitude, const bool absolute_amplitude, const double initial_phase, const unsigned int sampling_rate) 13 | : SineWaveGenerator(frequency, amplitude, absolute_amplitude, initial_phase + M_PI_2, sampling_rate) { } //Phase shift of pi/2 between cosine and sine 14 | 15 | template 16 | double CosineWaveGenerator::GetInitialPhase() const 17 | { 18 | return SineWaveGenerator::GetInitialPhase() - M_PI_2; //Phase shift of pi/2 between cosine and sine 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /common/comutils/format.cpp: -------------------------------------------------------------------------------- 1 | //String formatting functions 2 | // Andreas Unterweger, 2016-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #include 6 | #include 7 | 8 | #include "format.hpp" 9 | 10 | namespace comutils 11 | { 12 | std::string FormatValue(const double value, const unsigned int decimals) 13 | { 14 | std::ostringstream stream; 15 | stream << std::fixed << std::showpoint << std::setprecision(decimals) << value; 16 | return stream.str(); 17 | } 18 | 19 | std::string FormatLevel(const double value) 20 | { 21 | return FormatValue(value) + " dB"; 22 | } 23 | 24 | std::string FormatByte(const unsigned int value) 25 | { 26 | constexpr const char prefixes[] = {'k', 'M', 'G', 'T', 'E'}; 27 | std::ostringstream stream; 28 | if (value < 1024) 29 | stream << value << " "; 30 | else 31 | { 32 | int prefix_idx = -1; 33 | double converted_value = value; 34 | do 35 | { 36 | prefix_idx++; 37 | } while ((converted_value /= 1024) >= 1024); 38 | stream << std::fixed << FormatValue(converted_value) << " " << prefixes[prefix_idx] << 'i'; 39 | } 40 | stream << "B"; 41 | return stream.str(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /common/comutils/format.hpp: -------------------------------------------------------------------------------- 1 | //String formatting functions (header) 2 | // Andreas Unterweger, 2016-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #pragma once 6 | 7 | namespace comutils 8 | { 9 | //Formats a given floating-point value with the specified number of decimal places after the decimal point 10 | std::string FormatValue(const double value, const unsigned int decimals = 2); 11 | //Formats a decibel value 12 | std::string FormatLevel(const double value); 13 | //Formats a value representing a size in bytes, e.g., 2048 = 2.0 kiB 14 | std::string FormatByte(const unsigned int value); 15 | } 16 | -------------------------------------------------------------------------------- /common/comutils/math.cpp: -------------------------------------------------------------------------------- 1 | //Mathematical helper functions 2 | // Andreas Unterweger, 2017-2018 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #include 6 | 7 | #include "math.hpp" 8 | 9 | namespace comutils 10 | { 11 | double GetLevelFromValue(const double level, const double reference_value) 12 | { 13 | return 20 * log10(level / reference_value); 14 | } 15 | 16 | double GetValueFromLevel(const double level, const double reference_value) 17 | { 18 | return reference_value * pow(10, level / 20); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /common/comutils/math.hpp: -------------------------------------------------------------------------------- 1 | //Mathematical helper functions (header) 2 | // Andreas Unterweger, 2017-2018 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #pragma once 6 | 7 | namespace comutils 8 | { 9 | //Squares the given value 10 | template 11 | T sqr(const T value); 12 | 13 | //Converts an angle from degrees to radians 14 | constexpr double DegreesToRadians(const double degrees); 15 | //Converts an angle from radians to degrees 16 | constexpr double RadiansToDegrees(const double radians); 17 | 18 | //Converts a value into a level [dB] relative to the specified reference value 19 | double GetLevelFromValue(const double value, const double reference_value); 20 | //Converts a level [dB] into a value relative to the specified reference value 21 | double GetValueFromLevel(const double level, const double refrence_value); 22 | 23 | //Returns the factor by which the ith DCT coefficient is scaled after transform 24 | constexpr double GetDCTCoefficientScalingFactor(const unsigned int block_size, const unsigned int i); 25 | //Returns the factor by which the ith DCT coefficient is scaled after inverse transform 26 | constexpr double GetDCTCoefficientScalingFactor(const unsigned int block_size, const unsigned int i); 27 | //Returns the factor by which the 2-D-DCT coefficient with indices (i, j) is scaled after transform 28 | constexpr double Get2DDCTCoefficientScalingFactor(const unsigned int block_size, const unsigned int i, const unsigned int j); 29 | //Returns the factor by which the 2-D-DCT coefficient with indices (i, j) is scaled after inverse transform 30 | constexpr double Get2DIDCTCoefficientScalingFactor(const unsigned int block_size, const unsigned int i, const unsigned int j); 31 | } 32 | 33 | #include "math.impl.hpp" 34 | -------------------------------------------------------------------------------- /common/comutils/math.impl.hpp: -------------------------------------------------------------------------------- 1 | //Mathematical helper functions (template implementation) 2 | // Andreas Unterweger, 2016-2018 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #include 6 | 7 | //#include "math.hpp" 8 | 9 | namespace comutils 10 | { 11 | template 12 | T sqr(const T value) 13 | { 14 | return value * value; 15 | } 16 | 17 | constexpr double DegreesToRadians(const double degrees) 18 | { 19 | return M_PI * degrees / 180; 20 | } 21 | 22 | constexpr double RadiansToDegrees(const double radians) 23 | { 24 | return 180 * radians / M_PI; 25 | } 26 | 27 | constexpr double GetDCTCoefficientScalingFactor(const unsigned int block_size, const unsigned int i) 28 | { 29 | return sqrt((i == 0 ? 1.0 : 2.0) / block_size); //DC coefficient has an additional factor of sqrt(2) 30 | } 31 | 32 | constexpr double GetIDCTCoefficientScalingFactor(const unsigned int block_size, const unsigned int i) 33 | { 34 | return 1 / GetDCTCoefficientScalingFactor(block_size, i); 35 | } 36 | 37 | constexpr double Get2DDCTCoefficientScalingFactor(const unsigned int block_size, const unsigned int i, const unsigned int j) 38 | { 39 | return GetDCTCoefficientScalingFactor(block_size, i) * GetDCTCoefficientScalingFactor(block_size, j); 40 | } 41 | 42 | constexpr double Get2DIDCTCoefficientScalingFactor(const unsigned int block_size, const unsigned int i, const unsigned int j) 43 | { 44 | return GetIDCTCoefficientScalingFactor(block_size, i) * GetIDCTCoefficientScalingFactor(block_size, j); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /common/comutils/mixer.hpp: -------------------------------------------------------------------------------- 1 | //Wave form mixer class (header) 2 | // Andreas Unterweger, 2017-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | #include "wavegen.hpp" 10 | 11 | namespace comutils 12 | { 13 | //Defines a mixer of M wave forms 14 | template 15 | class WaveFormMixer : public WaveFormGenerator 16 | { 17 | public: 18 | //Constructs a new instance of WaveFormGenerator with the given channel parameters 19 | WaveFormMixer(const std::array*, M> &generators, const double mixing_factor = 1.0 / M, const unsigned int sampling_rate = 48000); 20 | 21 | //Replaces the component at the specified index with the given component 22 | void SetGenerator(const size_t generator_index, WaveFormGenerator * const generator); 23 | 24 | //Produces the next sample of the added weighted sum of all generators specified during construction. The weights are equal to the mixing factor. 25 | T GetNextSample(); 26 | 27 | //Produces the added weighted sum of the first N representative samples of each generator 28 | void GetRepresentativeSamples(const size_t N, T values[]) const; 29 | 30 | private: 31 | std::array*, M> generators; 32 | double mixing_factor; 33 | 34 | double MixValue(const double value) const; 35 | T ClipValue(const double value) const; 36 | void VerifyGenerator(const WaveFormGenerator * const generator) const; 37 | }; 38 | } 39 | 40 | #include "mixer.impl.hpp" 41 | -------------------------------------------------------------------------------- /common/comutils/mixer.impl.hpp: -------------------------------------------------------------------------------- 1 | //Wave form mixer class (template implementation) 2 | // Andreas Unterweger, 2017-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #include 6 | #include 7 | 8 | //#include "mixer.hpp" 9 | 10 | namespace comutils 11 | { 12 | template 13 | WaveFormMixer::WaveFormMixer(const std::array*, M> &generators, const double mixing_factor, const unsigned int sampling_rate) 14 | : WaveFormGenerator(sampling_rate), 15 | generators(generators), mixing_factor(mixing_factor) 16 | { 17 | for (const auto * const generator : generators) 18 | VerifyGenerator(generator); 19 | assert(mixing_factor >= 0.0 && mixing_factor <= 1.0); 20 | } 21 | 22 | template 23 | void WaveFormMixer::SetGenerator(const size_t generator_index, WaveFormGenerator * const generator) 24 | { 25 | assert(generator_index < M); 26 | this->generators[generator_index] = generator; 27 | VerifyGenerator(generator); 28 | } 29 | 30 | template 31 | double WaveFormMixer::MixValue(const double value) const 32 | { 33 | return mixing_factor * value; 34 | } 35 | 36 | template 37 | T WaveFormMixer::ClipValue(const double value) const 38 | { 39 | double clipped_value = value; 40 | if (clipped_value < WaveFormGenerator::min_amplitude) 41 | clipped_value = static_cast(WaveFormGenerator::min_amplitude); 42 | if (clipped_value > WaveFormGenerator::max_amplitude) 43 | clipped_value = static_cast(WaveFormGenerator::max_amplitude); 44 | return static_cast(clipped_value); 45 | } 46 | 47 | template 48 | T WaveFormMixer::GetNextSample() 49 | { 50 | double sample_value = 0.0; 51 | for (auto * const generator : generators) 52 | { 53 | if (generator) 54 | sample_value += MixValue(generator->GetNextSample()); 55 | } 56 | return ClipValue(sample_value); 57 | } 58 | 59 | template 60 | void WaveFormMixer::GetRepresentativeSamples(const size_t N, T values[]) const 61 | { 62 | std::vector sample_values(N, 0.0); 63 | for (auto * const generator : generators) 64 | { 65 | if (generator) 66 | { 67 | std::vector representative_samples(N); 68 | generator->GetRepresentativeSamples(N, representative_samples.data()); 69 | for (size_t i = 0; i < N; i++) 70 | sample_values[i] += MixValue(representative_samples[i]); 71 | } 72 | } 73 | std::transform(sample_values.begin(), sample_values.end(), values, [this](const double value) 74 | { 75 | return ClipValue(value); 76 | }); 77 | } 78 | 79 | template 80 | void WaveFormMixer::VerifyGenerator(const WaveFormGenerator * const generator) const 81 | { 82 | if (generator) 83 | assert(generator->GetSamplingRate() == this->sampling_rate); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /common/comutils/sinewave.hpp: -------------------------------------------------------------------------------- 1 | //Sine wave generator class (header) 2 | // Andreas Unterweger, 2017-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #pragma once 6 | 7 | #include "wavegen.hpp" 8 | 9 | namespace comutils 10 | { 11 | //Defines a generator for sinusodial wave forms 12 | template 13 | class SineWaveGenerator : public WaveFormGenerator 14 | { 15 | public: 16 | //Constructs a new instance of SineWaveGenerator with the given channel parameters. If absolute_amplitude is true, amplitude is used as is. If it is false, amplitude is used relative to the value range of T. 17 | SineWaveGenerator(const double frequency, const double amplitude = 1.0, const bool absolute_amplitude = false, const double initial_phase = 0, const unsigned int sampling_rate = 48000); 18 | 19 | //Returns the amplitude of the sine wave 20 | double GetAmplitude() const; 21 | //Returns the frequency of the sine wave 22 | double GetFrequency() const; 23 | //Returns the initial phase of the sine wave 24 | virtual double GetInitialPhase() const; 25 | 26 | //Sets the amplitude of the sine wave 27 | void SetAmplitude(const double amplitude); 28 | //Sets the frequency of the sine wave 29 | void SetFrequency(const double frequency); 30 | 31 | //Produces the next sample of the sine wave 32 | T GetNextSample(); 33 | 34 | //Produces first N samples of the sine wave 35 | void GetRepresentativeSamples(const size_t N, T values[]) const; 36 | 37 | private: 38 | double amplitude; 39 | double frequency; 40 | bool absolute_amplitude; 41 | double units_per_period; 42 | double phase; //Current phase 43 | double phase_shift; //Initial phase shift 44 | 45 | T GetSample(const double selected_phase) const; 46 | 47 | void SetPhaseShift(const double phase); 48 | }; 49 | } 50 | 51 | #include "sinewave.impl.hpp" 52 | -------------------------------------------------------------------------------- /common/comutils/sinewave.impl.hpp: -------------------------------------------------------------------------------- 1 | //Sine wave generator class (template implementation) 2 | // Andreas Unterweger, 2017-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #include 6 | #include 7 | 8 | //#include "sinewave.hpp" 9 | 10 | namespace comutils 11 | { 12 | template 13 | SineWaveGenerator::SineWaveGenerator(const double frequency, const double amplitude, const bool absolute_amplitude, const double initial_phase, const unsigned int sampling_rate) 14 | : WaveFormGenerator(sampling_rate), 15 | absolute_amplitude(absolute_amplitude), 16 | phase(0) 17 | { 18 | SetAmplitude(amplitude); 19 | SetFrequency(frequency); 20 | SetPhaseShift(initial_phase); 21 | } 22 | 23 | template 24 | double SineWaveGenerator::GetAmplitude() const 25 | { 26 | return this->amplitude; 27 | } 28 | 29 | template 30 | double SineWaveGenerator::GetFrequency() const 31 | { 32 | return this->frequency; 33 | } 34 | 35 | template 36 | double SineWaveGenerator::GetInitialPhase() const 37 | { 38 | if (this->frequency == 0.0) 39 | return 0; 40 | else 41 | return (2 * M_PI * this->phase_shift) / this->units_per_period; 42 | } 43 | 44 | template 45 | void SineWaveGenerator::SetAmplitude(const double amplitude) 46 | { 47 | if (!this->absolute_amplitude) 48 | assert(amplitude >= 0.0 && amplitude <= 1.0); 49 | this->amplitude = amplitude; 50 | } 51 | 52 | template 53 | void SineWaveGenerator::SetFrequency(const double frequency) 54 | { 55 | assert(frequency >= 0.0/* && frequency < this->sampling_rate / 2*/); //Uncomment if subsampling is undesired 56 | this->frequency = frequency; 57 | this->units_per_period = this->sampling_rate / this->frequency; 58 | } 59 | 60 | template 61 | T SineWaveGenerator::GetSample(const double selected_phase) const 62 | { 63 | assert(selected_phase >= 0.0); //Comment this if a purely positive phase is desired 64 | const double relative_amplitude = this->amplitude * (this->absolute_amplitude ? 1.0 : WaveFormGenerator::max_amplitude); 65 | const double current_amplitude = relative_amplitude * (this->frequency == 0 ? 1.0 : sin(2 * M_PI * this->frequency * (selected_phase + this->phase_shift) / this->sampling_rate)); //DC is multiplication with 1.0 66 | const T selected_value = static_cast(current_amplitude); 67 | return selected_value; 68 | } 69 | 70 | template 71 | T SineWaveGenerator::GetNextSample() 72 | { 73 | const T current_value = GetSample(this->phase); 74 | if (this->frequency != 0.0) 75 | this->phase = fmod(this->phase + 1, this->units_per_period); 76 | return current_value; 77 | } 78 | 79 | template 80 | void SineWaveGenerator::GetRepresentativeSamples(const size_t N, T values[]) const 81 | { 82 | for (size_t i = 0; i < N; i++) 83 | values[i] = GetSample(i); 84 | } 85 | 86 | template 87 | void SineWaveGenerator::SetPhaseShift(const double initial_phase) 88 | { 89 | if (this->frequency != 0.0) 90 | { 91 | const auto simple_initial_phase = fmod(initial_phase, 2 * M_PI); 92 | this->phase_shift = this->units_per_period * simple_initial_phase / (2 * M_PI); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /common/comutils/wavegen.hpp: -------------------------------------------------------------------------------- 1 | //Wave form generator interface (header) 2 | // Andreas Unterweger, 2017-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | namespace comutils 10 | { 11 | //Defines an abstract generator of wave forms 12 | template 13 | class WaveFormGenerator 14 | { 15 | public: 16 | //Constructs a new instance of WaveFormGenerator with the given channel parameters 17 | WaveFormGenerator(const unsigned int sampling_rate = 48000); 18 | 19 | //Produces the next sample of the wave form. To be implemented in child classes. 20 | virtual T GetNextSample() = 0; 21 | 22 | //Produces N representative samples of the wave form. To be implemented in child classes. 23 | virtual void GetRepresentativeSamples(const size_t N, T values[]) const = 0; 24 | 25 | //Returns the sampling rate used during construction 26 | unsigned int GetSamplingRate() const; 27 | 28 | protected: 29 | static constexpr T min_amplitude = std::numeric_limits::lowest(); 30 | static constexpr T max_amplitude = std::numeric_limits::max(); 31 | 32 | unsigned int sampling_rate; 33 | }; 34 | } 35 | 36 | #include "wavegen.impl.hpp" 37 | -------------------------------------------------------------------------------- /common/comutils/wavegen.impl.hpp: -------------------------------------------------------------------------------- 1 | //Wave form generator interface (template implementation) 2 | // Andreas Unterweger, 2017-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #include 6 | 7 | //#include "wavegen.hpp" 8 | 9 | namespace comutils 10 | { 11 | template 12 | WaveFormGenerator::WaveFormGenerator(const unsigned int sampling_rate) : sampling_rate(sampling_rate) 13 | { 14 | assert(sampling_rate > 0); 15 | } 16 | 17 | template 18 | unsigned int WaveFormGenerator::GetSamplingRate() const 19 | { 20 | return sampling_rate; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /common/imgutils/Makefile: -------------------------------------------------------------------------------- 1 | include ../auxbase.mak 2 | -------------------------------------------------------------------------------- /common/imgutils/colors.hpp: -------------------------------------------------------------------------------- 1 | //Color constants for drawing with OpenCV (header) 2 | // Andreas Unterweger, 2017-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | namespace imgutils 10 | { 11 | //Full red (RGB 255, 0, 0) 12 | const cv::Vec3b Red(0, 0, 255); 13 | //Full green (RGB 0, 255, 0) 14 | const cv::Vec3b Green(0, 255, 0); 15 | //Full blue (RGB 0, 0, 255) 16 | const cv::Vec3b Blue(255, 0, 0); 17 | 18 | //Full white (RGB 255, 255, 255) 19 | const cv::Vec3b White(255, 255, 255); 20 | //Full black (RGB 0, 0, 0) 21 | const cv::Vec3b Black(0, 0, 0); 22 | 23 | //Full purple (RGB 128, 0, 128) 24 | const cv::Vec3b Purple(128, 0, 128); 25 | } 26 | -------------------------------------------------------------------------------- /common/imgutils/combine.hpp: -------------------------------------------------------------------------------- 1 | //Image combination functions (header) 2 | // Andreas Unterweger, 2016-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace imgutils 12 | { 13 | //Position of combined images 14 | enum class CombinationMode { Horizontal, Vertical }; 15 | 16 | //Method to convert difference images 17 | enum class DifferenceConversionMode 18 | { 19 | Offset, //Adds 128 to the difference, clipping values below -128 and above 127, respectively 20 | Absolute, //Calculates absolute differences, i.e., without a sign 21 | Color //Converts positive differences to red values and negative differences to blue values 22 | }; 23 | 24 | //Concatenates N images (of potentially different sizes and color spaces) horizontally or vertically with black borders between them. If the images differ in size, they are border-filled to the largest width and height across all images. 25 | template 26 | cv::Mat CombineImages(const cv::Mat (&images)[N], const CombinationMode mode, const unsigned int border_size = 3); 27 | 28 | //Concatenates N images (of potentially different sizes and color spaces) horizontally or vertically with black borders between them. If the images differ in size, they are border-filled to the largest width and height across all images. 29 | cv::Mat CombineImages(const size_t N, const cv::Mat images[], const CombinationMode mode, const unsigned int border_size = 3); 30 | 31 | //Subtracts two (unsigned) 8-bit images from one another and returns a (signed) 16-bit difference image 32 | cv::Mat SubtractImages(const cv::Mat &image1, const cv::Mat &image2); 33 | 34 | //Converts a difference image (with one channel of signed 16-bit values) to illustrate it as an unsigned 8-bit image, e.g., with imshow 35 | cv::Mat ConvertDifferenceImage(const cv::Mat &difference_image, DifferenceConversionMode mode = DifferenceConversionMode::Color); 36 | } 37 | 38 | #include "combine.impl.hpp" 39 | -------------------------------------------------------------------------------- /common/imgutils/combine.impl.hpp: -------------------------------------------------------------------------------- 1 | //Image combination functions (template implementations) 2 | // Andreas Unterweger, 2016-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #include "common.hpp" 6 | 7 | //#include "combine.hpp" 8 | 9 | namespace imgutils 10 | { 11 | template 12 | cv::Mat CombineImages(const cv::Mat (&images)[N], const CombinationMode mode, const unsigned int border_size) //Comfort version for initializer lists (no need to explicitly specify N) 13 | { 14 | return CombineImages(N, images, mode, border_size); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /common/imgutils/drawtext.cpp: -------------------------------------------------------------------------------- 1 | //Helper functions for drawing aligned text 2 | // Andreas Unterweger, 2017-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #include 6 | 7 | #include 8 | 9 | #include "drawtext.hpp" 10 | 11 | namespace imgutils 12 | { 13 | static bool AlignmentContains(TextAlignment alignment, TextAlignment contained_alignment) 14 | { 15 | const auto all = static_cast::type>(alignment); 16 | const auto contained = static_cast::type>(contained_alignment); 17 | const auto result = (all & contained) == contained; 18 | return result; 19 | } 20 | 21 | void DrawText(cv::Mat_ &image, const std::string &text, const cv::Point &point, const TextAlignment alignment, const cv::Vec3b &color, const int cv_font_face, const double cv_font_scale) 22 | { 23 | int baseline; 24 | const auto text_size = cv::getTextSize(text, cv_font_face, cv_font_scale, 1, &baseline); 25 | auto offset_point = point; //Default is top-left (no offset) 26 | 27 | if (AlignmentContains(alignment, TextAlignment::Center)) 28 | offset_point.x -= text_size.width / 2; 29 | if (AlignmentContains(alignment, TextAlignment::Right)) 30 | offset_point.x -= text_size.width; 31 | if (AlignmentContains(alignment, TextAlignment::Middle)) 32 | offset_point.y += text_size.height / 2; 33 | if (AlignmentContains(alignment, TextAlignment::Bottom)) 34 | offset_point.y += text_size.height; 35 | cv::putText(image, text, offset_point, cv_font_face, cv_font_scale, color, 1, cv::LINE_AA); 36 | /*cv::drawMarker(image, point, imgutils::Red, cv::MARKER_SQUARE, 2); 37 | cv::drawMarker(image, offset_point + cv::Point(0, baseline), imgutils::Green, cv::MARKER_SQUARE, 2); //Enable for debugging*/ 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /common/imgutils/drawtext.hpp: -------------------------------------------------------------------------------- 1 | //Helper functions for drawing aligned text (header) 2 | // Andreas Unterweger, 2017-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | #include "colors.hpp" 10 | 11 | namespace imgutils 12 | { 13 | static_assert(sizeof(unsigned char) == 1, "unsigned char must be 8 bits in size"); 14 | 15 | //Way to align text 16 | enum class TextAlignment : unsigned char 17 | { 18 | //No alignment 19 | None = 0x00, 20 | 21 | //Horizontal alignments 22 | Left = 0x01, 23 | Center = 0x02, 24 | Right = 0x04, 25 | 26 | //Vertical alignments 27 | Top = 0x10, 28 | Middle = 0x20, 29 | Bottom = 0x40, 30 | 31 | //Combined alignments 32 | TopLeft = Top | Left, 33 | TopCenter = Top | Center, 34 | TopRight = Top | Right, 35 | MiddleLeft = Middle | Left, 36 | MiddleCenter = Middle | Center, 37 | MiddleRight = Middle | Right, 38 | BottomLeft = Bottom | Left, 39 | BottomCenter = Bottom | Center, 40 | BottomRight = Bottom | Right, 41 | }; 42 | 43 | //Draws the specified text with the defined alignment and parameters around the given point 44 | void DrawText(cv::Mat_ &image, const std::string &text, const cv::Point &point, const TextAlignment alignment, const cv::Vec3b &color, const int cv_font_face, const double cv_font_scale); 45 | } 46 | 47 | -------------------------------------------------------------------------------- /common/imgutils/imgmath.cpp: -------------------------------------------------------------------------------- 1 | //Helper functions for calculations on images 2 | // Andreas Unterweger, 2016-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #include "math.hpp" 6 | 7 | #include "imgmath.hpp" 8 | 9 | namespace imgutils 10 | { 11 | double SAD(const cv::Mat &difference_values) 12 | { 13 | assert(!difference_values.empty()); 14 | return norm(difference_values, cv::NORM_L1); 15 | } 16 | 17 | double SSD(const cv::Mat &difference_values) 18 | { 19 | assert(!difference_values.empty()); 20 | const auto sqrt_SSD = cv::norm(difference_values, cv::NORM_L2); 21 | return comutils::sqr(sqrt_SSD); //Square since L2 norm is square root of SSD 22 | } 23 | 24 | double MSE(const cv::Mat &difference_values) 25 | { 26 | assert(difference_values.total() != 0); 27 | return SSD(difference_values) / difference_values.total(); 28 | } 29 | 30 | double PSNR(const double MSE, const double max_error) 31 | { 32 | return comutils::GetLevelFromValue(max_error, sqrt(MSE)); 33 | } 34 | 35 | cv::Mat ImageLevelShift(const cv::Mat &image) 36 | { 37 | assert(image.type() == CV_8UC1); 38 | auto &original_image = static_cast>(image); 39 | cv::Mat_ shifted_image(image.rows, image.cols); 40 | std::transform(original_image.begin(), original_image.end(), shifted_image.begin(), LevelShift); 41 | return shifted_image; 42 | } 43 | 44 | cv::Mat ReverseImageLevelShift(const cv::Mat &image) 45 | { 46 | assert(image.type() == CV_64FC1); 47 | auto &original_image = static_cast>(image); 48 | cv::Mat_ shifted_image(image.rows, image.cols); 49 | std::transform(original_image.begin(), original_image.end(), shifted_image.begin(), ReverseLevelShift); 50 | return shifted_image; 51 | } 52 | 53 | cv::Mat GetRaw2DDCTBasisFunctionImage(const unsigned int block_size, const unsigned int i, const unsigned int j, const double amplitude) 54 | { 55 | assert(i < block_size && j < block_size); 56 | assert(amplitude >= 0.0 && amplitude <= 255.0); 57 | cv::Mat_ basis_image(cv::Size(block_size, block_size), 0.0); 58 | auto scaling_factor = comutils::Get2DIDCTCoefficientScalingFactor(block_size, i, j); 59 | basis_image(i, j) = LevelShift(amplitude) * scaling_factor; //Set one (selected) coefficient to the specified value after level-shifting (with scaling) 60 | cv::Mat reconstructed_basis_image; 61 | cv::idct(basis_image, reconstructed_basis_image); //The IDCT of the one coefficient yields the corresponding basis function 62 | return reconstructed_basis_image; 63 | } 64 | 65 | cv::Mat Get2DDCTBasisFunctionImage(const unsigned int block_size, const unsigned int i, const unsigned int j, const double amplitude) 66 | { 67 | const cv::Mat reconstructed_basis_image = GetRaw2DDCTBasisFunctionImage(block_size, i, j, amplitude); 68 | return ReverseImageLevelShift(reconstructed_basis_image); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /common/imgutils/imgmath.hpp: -------------------------------------------------------------------------------- 1 | //Helper functions for calculations on images (header) 2 | // Andreas Unterweger, 2017-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | namespace imgutils 10 | { 11 | //Calculates the sum of absolute differences of a difference image 12 | double SAD(const cv::Mat &difference_values); 13 | 14 | //Calculates the sum of squared differences of a difference image 15 | double SSD(const cv::Mat &difference_values); 16 | 17 | //Calculates the mean squared error of a difference image 18 | double MSE(const cv::Mat &difference_values); 19 | 20 | //Calculates the peak signal (maximum error) to noise ratio from the mean squared error 21 | double PSNR(const double MSE, const double max_error = 255); 22 | 23 | //Shifts all pixels of an unsigned 8-bit input image by half the range (128) and returns a 64-bit (double) output image 24 | cv::Mat ImageLevelShift(const cv::Mat &image); 25 | 26 | //Shifts a value by half of the 8-bit range (128) 27 | constexpr double LevelShift(const double value); 28 | //Shifts a value back by half of the 8-bit range (128) 29 | constexpr double ReverseLevelShift(const double value); 30 | 31 | //Shifts all pixels of a 64-bit (double) input image back by half the range (128) and returns an unsigned 8-bit output image 32 | cv::Mat ReverseImageLevelShift(const cv::Mat &image); 33 | 34 | //Generates a 64-bit (dobule) image of the 2-D-DCT basis function with indices (i, j) and the specified amplitude. The default amplitude is the maximum 8-bit amplitude of 255 from the range [0;255] 35 | cv::Mat GetRaw2DDCTBasisFunctionImage(const unsigned int block_size, const unsigned int i, const unsigned int j, const double amplitude); 36 | //Generates an (unsigned) 8-bit image of the 2-D-DCT basis function with indices (i, j) and the specified amplitude. The default amplitude is the maximum 8-bit amplitude of 255 from the range [0;255] 37 | cv::Mat Get2DDCTBasisFunctionImage(const unsigned int block_size, const unsigned int i, const unsigned int j, const double amplitude = 255.0); 38 | } 39 | 40 | #include "imgmath.impl.hpp" 41 | -------------------------------------------------------------------------------- /common/imgutils/imgmath.impl.hpp: -------------------------------------------------------------------------------- 1 | //Helper functions for calculations on images (template implementations) 2 | // Andreas Unterweger, 2017-2018 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #pragma once 6 | 7 | //#include "imgmath.hpp" 8 | 9 | namespace imgutils 10 | { 11 | constexpr double LevelShift(const double value) 12 | { 13 | return value - 128; 14 | } 15 | 16 | constexpr double ReverseLevelShift(const double value) 17 | { 18 | return value + 128; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /common/imgutils/multiwin.hpp: -------------------------------------------------------------------------------- 1 | //Multi-window arrangements (header) 2 | // Andreas Unterweger, 2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | #include 10 | 11 | #include "window.hpp" 12 | 13 | namespace imgutils 14 | { 15 | //Position of windows in a group of windows 16 | enum class WindowAlignment { Horizontal, Vertical }; 17 | 18 | //Represents an aligned group of multiple windows 19 | class MultiWindow : public VisibleWindow 20 | { 21 | public: 22 | //Creates a new group of windows from the given windows with the specified alignment 23 | MultiWindow(const std::vector &windows, const WindowAlignment alignment, const std::vector &hidden_windows = {}); 24 | //Hides the window group 25 | ~MultiWindow() override; 26 | 27 | //The set of windows which will not be shown when Show() of the whole group is called 28 | std::vector hidden_windows; 29 | 30 | //Returns the total width and height of the group of windows 31 | cv::Size GetSize() const; 32 | //Throws an exception as the size of a group of windows cannot be set in a meaningful way 33 | void SetSize(const cv::Size &size) override; 34 | 35 | //Sets the top-left position of the group of windows, thereby updating the positions of each individual window 36 | void SetPosition(const cv::Point &position) override; 37 | 38 | //Updates the window group (i.e., all windows of the group) if it is visible and set its position 39 | void Update(const bool first_update = false) override; 40 | 41 | //Throws an exception 42 | int Wait(const int timeout = 0) override; 43 | //Waits for the minimum amount of time (1) and returns the key pressed in any of the windows of the window group during this time, if any, or -1 otherwise. 44 | int WaitMinimal() override; 45 | protected: 46 | //The windows to be aligned 47 | std::vector windows; 48 | //How the windows are aligned 49 | const WindowAlignment alignment; 50 | 51 | //Creates the window group, i.e., it shows the aligned windows except for the ones which are to remain hidden 52 | void CreateWindow() override; 53 | //Does nothing 54 | void AfterCreateWindow() override; 55 | //Destroys the window group, i.e., it hides the aligned windows, including the ones which have not been shown as they remained hidden 56 | void DestroyWindow() override; 57 | 58 | //Creates a new empty group of windows with the specified alignment. The group needs to be initialized by SetWindows later 59 | MultiWindow(const WindowAlignment alignment); 60 | //Sets the specified groups of windows 61 | void SetWindows(const std::vector &windows); 62 | }; 63 | } 64 | -------------------------------------------------------------------------------- /common/imgutils/plot.impl.hpp: -------------------------------------------------------------------------------- 1 | //Helper class for plotting points and lines (template implementation) 2 | // Andreas Unterweger, 2017-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #include 6 | 7 | //#include "plot.hpp" 8 | 9 | namespace imgutils 10 | { 11 | template 12 | PointSet::PointSet(const std::vector &y_coordinates, const double x_scale, const cv::Vec3b &point_color, const bool interconnect_points, const bool draw_sample_bars, const unsigned int line_width) 13 | : point_color(point_color), interconnect_points(interconnect_points), draw_sample_bars(draw_sample_bars), 14 | line_width(line_width) 15 | { 16 | size_t i = 0; 17 | points.resize(y_coordinates.size()); 18 | std::transform(y_coordinates.begin(), y_coordinates.end(), points.begin(), [&i, &x_scale](const T y_coordinate) 19 | { 20 | return cv::Point2d(x_scale * i++, y_coordinate); 21 | }); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /common/imgutils/winctrl.cpp: -------------------------------------------------------------------------------- 1 | //Window controls 2 | // Andreas Unterweger, 2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #include 6 | 7 | #include 8 | 9 | #include "winctrl.hpp" 10 | 11 | namespace imgutils 12 | { 13 | WindowControlBase::WindowControlBase(const std::string &name, Window &parent, const bool requires_hidden_window) 14 | : name(name), parent(parent), requires_hidden_window(requires_hidden_window) 15 | { 16 | parent.AddControl(this, requires_hidden_window); 17 | } 18 | 19 | WindowControlBase::~WindowControlBase() 20 | { 21 | parent.RemoveControl(this, requires_hidden_window); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /common/sndutils/Makefile: -------------------------------------------------------------------------------- 1 | include ../auxbase.mak 2 | -------------------------------------------------------------------------------- /common/sndutils/player.hpp: -------------------------------------------------------------------------------- 1 | //Audio playback helper class (header) 2 | // Andreas Unterweger, 2017-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include "wavegen.hpp" 13 | 14 | namespace sndutils 15 | { 16 | //Plays back raw audio streams of base type T on the default playback device 17 | template 18 | class AudioPlayer 19 | { 20 | public: 21 | //Constructs a new instance of AudioPlayer with the given playback device parameters. Make sure that the used device is configured accordingly. 22 | AudioPlayer(const unsigned int sampling_rate = 48000, const size_t number_of_channels = 2); 23 | ~AudioPlayer(); 24 | 25 | //Plays back the wave form produced by the specified generator asynchronously until Stop() is called 26 | void Play(comutils::WaveFormGenerator &generator); 27 | //Halts previously started playback 28 | void Stop(); 29 | //Pauses previusly started playback 30 | void Pause(); 31 | //Resumes previously started playback 32 | void Resume(); 33 | //Returns whether playback has been started (even when currently paused) 34 | bool IsPlaying() const; 35 | //Returns whether there is playback at the moment 36 | bool IsPlayingBack() const; 37 | 38 | private: 39 | ao_sample_format sample_format; 40 | ao_device *playback_device; 41 | std::atomic_bool playing; 42 | std::atomic_bool paused; 43 | std::thread worker; 44 | }; 45 | } 46 | 47 | #include "player.impl.hpp" 48 | -------------------------------------------------------------------------------- /common/tools.mak: -------------------------------------------------------------------------------- 1 | #Path definitions for the tools used by the Makefiles 2 | # Andreas Unterweger, 2016-2022 3 | #This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | CXX ?= g++ 6 | PKGCFG ?= pkg-config 7 | RM ?= rm -f 8 | MAKE ?= make 9 | CD ?= cd 10 | ECHO ?= echo 11 | -------------------------------------------------------------------------------- /content-based_image_retrieval/Makefile: -------------------------------------------------------------------------------- 1 | PARTS = 3d 2 | 3 | ORDER := mean_feature histogram quantization 4 | 5 | include ../common/appbase.mak 6 | -------------------------------------------------------------------------------- /content-based_image_retrieval/histogram_readme.md: -------------------------------------------------------------------------------- 1 | RGB image histograms 2 | ==================== 3 | 4 | **Short description**: Illustration of image histograms (Illustrates the different histograms of an RGB image) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Complete 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/histogram.png) 14 | 15 | The channels of an RGB image (left in the *Image and its histogram* window) can be separated to calculate per-channel histograms (right). Each of the three histograms represents the frequency of brighness values in the red, green and blue channel, respectively. The number of histogram bins impacts how many intensities are grouped together, i.e., which values are combined for the frequency calculation. 16 | 17 | Usage 18 | ----- 19 | 20 | Change the number of bins (see parameters below) to see the frequency values in the histogram change due to the different grouping. Observe that the general shape of the histogram stays about the same, but details disappear when using a small number of bins. For the default program parameters, observe that the high frequency of bright-red intensities (high values in the red histogram) reflects the red-ish tone of the image. 21 | 22 | ![Screenshot after setting the number of bins to 64](../screenshots/histogram_64_bins.png) 23 | 24 | Available actions 25 | ----------------- 26 | 27 | None. *Note: See below for parameters to change.* 28 | 29 | Interactive parameters 30 | ---------------------- 31 | 32 | * **Bins** (track bar in the *Image and its histogram* window): Allows changing the number of bins for calculating the histogram. The same number of bins is used for all histograms. 33 | 34 | Program parameters 35 | ------------------ 36 | 37 | * **Input image**: File path of the image to calculate the histograms of. 38 | 39 | Hard-coded parameters 40 | --------------------- 41 | 42 | None 43 | 44 | Known issues 45 | ------------ 46 | 47 | None 48 | 49 | Missing features 50 | ---------------- 51 | 52 | None 53 | 54 | License 55 | ------- 56 | 57 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. 58 | -------------------------------------------------------------------------------- /content-based_image_retrieval/histogram_test: -------------------------------------------------------------------------------- 1 | ../testdata/images/Lenna.png 2 | ../testdata/images/news.png 3 | -------------------------------------------------------------------------------- /content-based_image_retrieval/mean_feature_readme.md: -------------------------------------------------------------------------------- 1 | Mean RGB image features 2 | ======================= 3 | 4 | **Short description**: Illustration of mean RGB feature vectors (Illustrates images and their feature vectors when using mean RGB features) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Near-complete (non-crucial features missing) 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/mean_feature.png) 14 | 15 | The average red, green and blue intensity of an RGB image can be visualized by a three-dimensional vector (window *Feature vectors*). For multiple images, these vectors consisting of mean R, G and B values, can be used as features, e.g., to compute the similarity of two images and to find similar images. 16 | 17 | Usage 18 | ----- 19 | 20 | Zoom into the collection of feature vectors to see the images corresponding to each vector on top of them. Move the camera to change the perspective. Observe that images of similar color and brightness are closer to one another, while dissimilar images are farther apart. 21 | 22 | ![Screenshot after zooming in](../screenshots/mean_feature_zoomed.png) 23 | 24 | Available actions 25 | ----------------- 26 | 27 | None 28 | 29 | Interactive parameters 30 | ---------------------- 31 | 32 | None. *Note: The camera position and zoom can be changed using the mouse.* 33 | 34 | Program parameters 35 | ------------------ 36 | 37 | * **Input images** (one image per parameter): File path of the images to calculate mean RGB feature vectors of. *Note: At least one parameter (image) must be specified.* 38 | 39 | Hard-coded parameters 40 | --------------------- 41 | 42 | * `use_normalization`: If true, additional l1 normalization is performed to eliminate the impact of image brightness. If false (default), no l1 normalization is performed and brightness has a significant impact as described above. 43 | * `thumbnail_size` (local to `AddImageVisualization`): Width and height of the images in the visualization in relative coordinates. 44 | 45 | Known issues 46 | ------------ 47 | 48 | None 49 | 50 | Missing features 51 | ---------------- 52 | 53 | * **Normalization**: There is no option to normalize the mean values to illustrate features that are independent of overall image brightness. 54 | 55 | License 56 | ------- 57 | 58 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. 59 | -------------------------------------------------------------------------------- /content-based_image_retrieval/mean_feature_test: -------------------------------------------------------------------------------- 1 | ../testdata/images/*.png 2 | -------------------------------------------------------------------------------- /content-based_image_retrieval/quantization_readme.md: -------------------------------------------------------------------------------- 1 | RGB color space quantization 2 | ============================ 3 | 4 | **Short description**: Illustration of color space quantization (Illustrates the effect of quantization on the RGB color space) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Complete 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/quantization.png) 14 | 15 | The RGB color space can be visualized as a three-dimensional cube consisting of smaller cuboid elements (window *Color space elements*). Each of the elements represents one color that can be mixed in the RGB color space. The R, G and B portions of each of the element are proportional to its position in space, with each spatial dimension representing one of the primary colors. The number of elements per spatial dimension determines the level of quantization of the visualized RGB color space. 16 | 17 | Usage 18 | ----- 19 | 20 | Change the number of elements (see parameters below) to see the quantized colors of the RGB color space change. Observe that a small number of elements only allows for mixing a small subset of possible colors, while the maximum number of elements corresponds to an 24-bit color space (8 bits per channel) without additional quantization. 21 | 22 | ![Screenshot after setting the number of elements to 8](../screenshots/quantization_8.png) 23 | 24 | Available actions 25 | ----------------- 26 | 27 | None. *Note: See below for parameters to change.* 28 | 29 | Interactive parameters 30 | ---------------------- 31 | 32 | * **Elements** (track bar in the *Color space elements* window): Allows changing the number of cuboid elements per dimension, i.e., number of possible values per color channel after quantization. 33 | 34 | *Note: Additionally, the camera position and zoom can be changed using the mouse.* 35 | 36 | Program parameters 37 | ------------------ 38 | 39 | None 40 | 41 | Hard-coded parameters 42 | --------------------- 43 | 44 | * `minimum_quantization_level` (local to `quantization_data`): The lowest possible number of quantization levels (default 2). This is also the lower limit of the *Elements* parameter. 45 | * `maximum_quantization_level` (local to `quantization_data`): The highest possible number of quantization levels (default 256). This is also the upper limit of the *Elements* parameter. 46 | * `initial_quantization_level` (local to `quantization_data`): The value of the *Elements* parameter at the start of the program (default 4). 47 | 48 | Known issues 49 | ------------ 50 | 51 | None 52 | 53 | Missing features 54 | ---------------- 55 | 56 | None 57 | 58 | License 59 | ------- 60 | 61 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. 62 | -------------------------------------------------------------------------------- /content-based_image_retrieval/quantization_test: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /create_archive.sh: -------------------------------------------------------------------------------- 1 | #Utility to create a clean compressed archive from this directory 2 | # Andreas Unterweger, 2016-2018 3 | #This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | name=$(basename "$PWD") 6 | make clean > /dev/null 7 | cd .. 8 | tar --exclude="$name/.git" --exclude="$name/.gitignore" -czf "$name.tar.gz" "$name" 9 | -------------------------------------------------------------------------------- /create_mini_archive.sh: -------------------------------------------------------------------------------- 1 | #Utility to create a clean compressed archive from this directory with essential files only 2 | # Andreas Unterweger, 2018-2019 3 | #This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | name=$(basename "$PWD") 6 | make clean > /dev/null 7 | cd .. 8 | (find "$name" -type f | grep -v '^'$name'\($\|/\(.git\|.gitignore\|screenshots\|testdata\|[^/]\+.sh\)\)' && find "$name/screenshots/" -iname '*.txt' && find "$name/testdata/" -iname '*.txt') | tar czf "${name}_mini.tar.gz" --files-from - 9 | -------------------------------------------------------------------------------- /features/Makefile: -------------------------------------------------------------------------------- 1 | ORDER := gaussian difference_of_gaussians sift_keypoints sift_keypoint_matching panoramic_image matching_perspective 2 | 3 | include ../common/appbase.mak 4 | -------------------------------------------------------------------------------- /features/difference_of_gaussians_test: -------------------------------------------------------------------------------- 1 | ../testdata/images/Lenna.png 2 | ../testdata/images/recttext.png 3 | -------------------------------------------------------------------------------- /features/gaussian.cpp: -------------------------------------------------------------------------------- 1 | //Illustration of Gaussian filtering 2 | // Andreas Unterweger, 2017-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include "common.hpp" 11 | #include "combine.hpp" 12 | #include "window.hpp" 13 | 14 | class Gaussian_data 15 | { 16 | protected: 17 | imgutils::Window window; 18 | 19 | using TrackBarType = imgutils::TrackBar; 20 | TrackBarType sigma_trackbar; 21 | 22 | const cv::Mat image; 23 | 24 | static void UpdateImage(Gaussian_data &data) 25 | { 26 | const cv::Mat &image = data.image; 27 | const int sigma_percent = data.sigma_trackbar.GetValue(); 28 | const double sigma = sigma_percent / 100.0; 29 | cv::Mat blurred_image; 30 | GaussianBlur(image, blurred_image, cv::Size(), sigma); 31 | const cv::Mat combined_image = imgutils::CombineImages({image, blurred_image}, imgutils::CombinationMode::Horizontal); 32 | data.window.UpdateContent(combined_image); 33 | } 34 | 35 | static constexpr auto window_name = "Original vs. blurred"; 36 | static constexpr auto sigma_trackbar_name = "Sigma [%]"; 37 | 38 | static constexpr auto min_sigma = 0.01; 39 | static constexpr auto max_sigma = 20.0; 40 | static constexpr auto default_sigma = 2.0; 41 | static_assert(min_sigma <= max_sigma, "The maximum sigma value cannot be greater than the minimum sigma value"); 42 | static_assert(default_sigma <= max_sigma && default_sigma >= min_sigma, "The maximum sigma value cannot be greater than the default sigma value, and the minimum sigma value cannot be smaller than the default sigma value"); 43 | public: 44 | Gaussian_data(const cv::Mat &image) 45 | : window(window_name), 46 | sigma_trackbar(sigma_trackbar_name, window, static_cast(max_sigma * 100), static_cast(min_sigma * 100), static_cast(default_sigma * 100), UpdateImage, *this), //sigma = 2 (200%) by default 47 | image(image) 48 | { 49 | UpdateImage(*this); //Update with default values 50 | } 51 | 52 | void ShowImage() 53 | { 54 | window.ShowInteractive(); 55 | } 56 | }; 57 | 58 | static void ShowImage(const cv::Mat &image) 59 | { 60 | Gaussian_data data(image); 61 | data.ShowImage(); 62 | } 63 | 64 | int main(const int argc, const char * const argv[]) 65 | { 66 | if (argc != 2) 67 | { 68 | std::cout << "Illustrates the effect of sigma of a Gaussian filter." << std::endl; 69 | std::cout << "Usage: " << argv[0] << " " << std::endl; 70 | return 1; 71 | } 72 | const auto filename = argv[1]; 73 | const cv::Mat image = cv::imread(filename); 74 | if (image.empty()) 75 | { 76 | std::cerr << "Could not read input image '" << filename << "'" << std::endl; 77 | return 2; 78 | } 79 | ShowImage(image); 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /features/gaussian_readme.md: -------------------------------------------------------------------------------- 1 | Gaussian filtering 2 | ================== 3 | 4 | **Short description**: Illustration of Gaussian filtering (Illustrates the effect of sigma of a Gaussian filter) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Complete 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/gaussian.png) 14 | 15 | A two-dimensional Gaussian filter can be used to blur images. To do so, the original image (left in the *Original vs. blurred* window) is convolved with a normalized windowed two-dimensional Gaussian function with a standard deviation of sigma to yield the filtered image (right). Suitable window sizes can be computed automatically. 16 | 17 | Usage 18 | ----- 19 | 20 | Change the value of sigma (see parameters below) to see the filtered image become more blurry due to the higher standard deviation. Observe that image features with high spatial frequencies, e.g., steep edges, disappear, while features with low spatial frequencies, e.g., large single-color regions, are retained. 21 | 22 | ![Screenshot after setting sigma to 5](../screenshots/gaussian_sigma5.png) 23 | 24 | Available actions 25 | ----------------- 26 | 27 | None. *Note: See below for parameters to change.* 28 | 29 | Interactive parameters 30 | ---------------------- 31 | 32 | * **Sigma** (track bar in the *Original vs. blurred* window): Allows changing the standard deviation (in the X and Y direction) of the Gaussian filter in percent. 33 | 34 | Program parameters 35 | ------------------ 36 | 37 | * **Input image**: File path of the image to apply the Gaussian filter to. 38 | 39 | Hard-coded parameters 40 | --------------------- 41 | 42 | * `min_sigma` (local to `Gaussian_data`): Minimum value of sigma allowed to be configured for the standard deviation. 43 | * `max_sigma` (local to `Gaussian_data`): Maximum value of sigma allowed to be configured for the standard deviation. 44 | * `default_sigma` (local to `Gaussian_data`): Initial value of standard deviation when the program is started. 45 | 46 | Known issues 47 | ------------ 48 | 49 | None 50 | 51 | Missing features 52 | ---------------- 53 | 54 | None 55 | 56 | License 57 | ------- 58 | 59 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. -------------------------------------------------------------------------------- /features/gaussian_test: -------------------------------------------------------------------------------- 1 | ../testdata/images/recttext.png 2 | ../testdata/images/Lenna.png 3 | -------------------------------------------------------------------------------- /features/matching_perspective_readme.md: -------------------------------------------------------------------------------- 1 | Matching for perspective transform 2 | ================================== 3 | 4 | **Short description**: Illustration of SIFT matching for finding a perspective transform (Illustrates how to find an image with a perspective transform within another image) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Done 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/matching_perspective.png) 14 | 15 | One image (left in the *Images combined* window) can be found within another (right) even when the perspective is changed slightly. To do so, keypoints in both images are computed and matched to estimate a transform from the first to the second image. After applying this transform to the frame of the first image, it can be found in the second image (red deformed rectangle). 16 | 17 | Usage 18 | ----- 19 | 20 | Observe that the first image is, for the most part, contained within the second. The left-most portion is an exception. The slight change in perspective does not impact the matching, nor do occlusions like the one around the tip of the rightmost green cone. Note that the estimated perspective transform is not entirely correct due to the limitations of homography-based mapping on non-planar objects. 21 | 22 | ![Screenshot with a different input file](../screenshots/matching_perspective_tractor.png) 23 | 24 | Available actions 25 | ----------------- 26 | 27 | Press Q to quit. Use any other key to advance to the next frame. *Notes: Pressing any key in the last frame terminates the program.* 28 | 29 | Interactive parameters 30 | ---------------------- 31 | 32 | None. 33 | 34 | Program parameters 35 | ------------------ 36 | 37 | * **First image**: File path of the first image to find within the second. 38 | * **Second image**: File path of the second image to find the first one in. This parameter can also specify the file path of a video consisting of multiple second images. If *-* is specified, a webcam is used. 39 | * (optional) **Waiting time between images**: Time in ms to wait after each processed second image. The default value 0 denotes infinite waiting, which can be interrupted by a key press. 40 | 41 | Hard-coded parameters 42 | --------------------- 43 | 44 | * `line_width` (local to `DrawImageRectangle`): Width of the transformed image frame's lines in pixels. 45 | 46 | Known issues 47 | ------------ 48 | 49 | None 50 | 51 | Missing features 52 | ---------------- 53 | 54 | None 55 | 56 | License 57 | ------- 58 | 59 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. 60 | -------------------------------------------------------------------------------- /features/matching_perspective_test: -------------------------------------------------------------------------------- 1 | ../testdata/images/im2.png ../testdata/images/im6.png 2 | ../testdata/images/tractor.png ../testdata/images/t%03d.png 3 | ../testdata/images/tractor.png - 1 4 | -------------------------------------------------------------------------------- /features/panoramic_image.cpp: -------------------------------------------------------------------------------- 1 | //Illustration of panoramic images 2 | // Andreas Unterweger, 2017-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #include "colors.hpp" 15 | #include "combine.hpp" 16 | #include "window.hpp" 17 | 18 | static std::vector LoadImages(std::vector image_paths) 19 | { 20 | using namespace std::string_literals; 21 | std::vector images(image_paths.size()); 22 | std::transform(image_paths.begin(), image_paths.end(), images.begin(), 23 | [](const char * const filename) 24 | { 25 | const cv::Mat image = cv::imread(filename); 26 | if (image.empty()) 27 | throw std::runtime_error("Could not read image '"s + filename + "'"); 28 | return image; 29 | }); 30 | return images; 31 | } 32 | 33 | static cv::Mat StitchImages(const std::vector &images) 34 | { 35 | assert(images.size() >= 2); 36 | cv::Mat stitched_image; 37 | auto stitcher = cv::Stitcher::create(); 38 | const auto status = stitcher->stitch(images, stitched_image); 39 | if (status != cv::Stitcher::Status::OK) 40 | throw std::runtime_error("Stitching failed with error " + std::to_string(status)); 41 | return stitched_image; 42 | } 43 | 44 | static void ShowImages(const std::vector &images) 45 | { 46 | constexpr auto window_name = "Images combined"; 47 | imgutils::Window window(window_name); 48 | const cv::Mat original_images = imgutils::CombineImages(images.size(), images.data(), imgutils::CombinationMode::Horizontal); 49 | const cv::Mat panoramic_image = StitchImages(images); 50 | const cv::Mat combined_image = imgutils::CombineImages({original_images, panoramic_image}, imgutils::CombinationMode::Vertical); 51 | window.UpdateContent(combined_image); 52 | window.ShowInteractive(); 53 | } 54 | 55 | int main(const int argc, const char * const argv[]) 56 | { 57 | if (argc < 3) 58 | { 59 | std::cerr << "Usage: " << argv[0] << " [ [ ... []]]" << std::endl; 60 | return 1; 61 | } 62 | std::vector image_paths(argv + 1, argv + argc); 63 | try 64 | { 65 | const auto images = LoadImages(image_paths); 66 | ShowImages(images); 67 | } 68 | catch (const std::runtime_error &e) 69 | { 70 | std::cerr << e.what() << std::endl; 71 | } 72 | return 0; 73 | } 74 | -------------------------------------------------------------------------------- /features/panoramic_image_readme.md: -------------------------------------------------------------------------------- 1 | Panoramic image 2 | =============== 3 | 4 | **Short description**: Illustration of panoramic images (Illustrates how a panoramic image can be created from multiple single images) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Done 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/panoramic_image.png) 14 | 15 | Multiple images (top in the *Images combined* window) can be merged into a panoramic image (bottom) under certain conditions. To do so, keypoints in both images are computed and matched to estimate transformations between the images. After compensating for these transformations, the images are stitched together. For this to work, the images need to have relatively small differences in perspective. 16 | 17 | Usage 18 | ----- 19 | 20 | Observe that both images are warped to fit together without overlapping. This forms a panoramic image. The errors around the bootom of the tree stems from the occlusions (missing pixel data) due to the differences in perspective between the images. 21 | 22 | Available actions 23 | ----------------- 24 | 25 | None 26 | 27 | Interactive parameters 28 | ---------------------- 29 | 30 | None 31 | 32 | Program parameters 33 | ------------------ 34 | 35 | * **First image**: File path of the first image. 36 | * **Second image**: File path of the second image to be combined with the first. 37 | * (optional) **Third image**: File path of the third image to be combined with the first two. 38 | * ... 39 | 40 | *Note: This program supports an arbitrary number of images (parameters).* 41 | 42 | Hard-coded parameters 43 | --------------------- 44 | 45 | None 46 | 47 | Known issues 48 | ------------ 49 | 50 | None 51 | 52 | Missing features 53 | ---------------- 54 | 55 | None 56 | 57 | License 58 | ------- 59 | 60 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. -------------------------------------------------------------------------------- /features/panoramic_image_test: -------------------------------------------------------------------------------- 1 | ../testdata/images/pan001.png ../testdata/images/pan003.png 2 | ../testdata/images/pan001.png ../testdata/images/pan003.png ../testdata/images/pan004.png 3 | ../testdata/images/pan* 4 | -------------------------------------------------------------------------------- /features/sift_keypoint_matching_readme.md: -------------------------------------------------------------------------------- 1 | SIFT keypoint matching 2 | ====================== 3 | 4 | **Short description**: Illustration of SIFT keypoint matching (Illustrates how SIFT keypoints in two images can be matched) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Complete 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/sift_keypoint_matching.png) 14 | 15 | SIFT can be used to find points in two different images (top in the *First and second image* window) which are robust to several types transformations. These keypoints and their associated descriptors can be matched to find corresponding points in the two images. To achieve good performance, only close matches are retained in a filtering process. 16 | 17 | Usage 18 | ----- 19 | 20 | Change the match index (see parameters below) to visualize the corresponding points (connected by the colored line at the bottom of the *First and second image* window) one by one. Observe that not all matches are actually correct, even though they are considered to be close. 21 | 22 | ![Screenshot after selecting the 92th point](../screenshots/sift_keypoint_matching_point92.png) 23 | 24 | Available actions 25 | ----------------- 26 | 27 | None. *Note: See below for parameters to change.* 28 | 29 | Interactive parameters 30 | ---------------------- 31 | 32 | * **Match index** (track bar in the *First and second image* window): Allows changing the visualized match, i.e., the pair of supposedly-matching keypoints. The range of this index is bound by the number of filtered matches. 33 | 34 | Program parameters 35 | ------------------ 36 | 37 | * **First image**: File path of the first image to detect keypoints in. 38 | * **Second image**: File path of the second image to detect keypoints in. 39 | 40 | Hard-coded parameters 41 | --------------------- 42 | 43 | * `line_width` (local to `match_data::DrawMatches`): Width of the line connecting the supposedly-matching keypoints. 44 | 45 | Known issues 46 | ------------ 47 | 48 | None 49 | 50 | Missing features 51 | ---------------- 52 | 53 | None 54 | 55 | License 56 | ------- 57 | 58 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. 59 | -------------------------------------------------------------------------------- /features/sift_keypoint_matching_test: -------------------------------------------------------------------------------- 1 | ../testdata/images/f001.png ../testdata/images/f010.png 2 | -------------------------------------------------------------------------------- /features/sift_keypoints.cpp: -------------------------------------------------------------------------------- 1 | //Illustration of SIFT keypoints 2 | // Andreas Unterweger, 2017-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include "combine.hpp" 11 | #include "window.hpp" 12 | 13 | static void DetectFeatures(const cv::Mat &image, std::vector &keypoints) 14 | { 15 | auto feature_detector = cv::SIFT::create(); 16 | feature_detector->detect(image, keypoints); 17 | } 18 | 19 | static cv::Mat DrawKeypoints(const cv::Mat &image, const std::vector &keypoints) 20 | { 21 | cv::Mat image_with_keypoints; 22 | drawKeypoints(image, keypoints, image_with_keypoints, cv::Scalar::all(-1), cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS); 23 | return image_with_keypoints; 24 | } 25 | 26 | static cv::Mat VisualizeKeypoints(const cv::Mat &image) 27 | { 28 | std::vector keypoints; 29 | DetectFeatures(image, keypoints); 30 | const cv::Mat image_with_keypoints = DrawKeypoints(image, keypoints); 31 | return image_with_keypoints; 32 | } 33 | 34 | static void ShowImage(const cv::Mat &image) 35 | { 36 | constexpr auto window_name = "Image without and with keypoints"; 37 | imgutils::Window window(window_name); 38 | const cv::Mat image_with_keypoints = VisualizeKeypoints(image); 39 | const cv::Mat combined_image = imgutils::CombineImages({image, image_with_keypoints}, imgutils::CombinationMode::Horizontal); 40 | window.UpdateContent(combined_image); 41 | window.ShowInteractive(); 42 | } 43 | 44 | int main(const int argc, const char * const argv[]) 45 | { 46 | if (argc != 2) 47 | { 48 | std::cout << "Illustrates the SIFT keypoints of an image" << std::endl; 49 | std::cout << "Usage: " << argv[0] << " " << std::endl; 50 | return 1; 51 | } 52 | const auto image_filename = argv[1]; 53 | const cv::Mat image = cv::imread(image_filename); 54 | if (image.empty()) 55 | { 56 | std::cerr << "Could not read input image '" << image_filename << "'" << std::endl; 57 | return 2; 58 | } 59 | ShowImage(image); 60 | return 0; 61 | } 62 | -------------------------------------------------------------------------------- /features/sift_keypoints_readme.md: -------------------------------------------------------------------------------- 1 | SIFT keypoints 2 | ============== 3 | 4 | **Short description**: Illustration of SIFT keypoints (Illustrates the SIFT keypoints of an image) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Complete 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/sift_keypoints.png) 14 | 15 | SIFT can be used to find points in an image (window *Image without and with keypoints*) which are robust to several types transformations. If the image was taken from a different distance or perspective, many of the same points would likely be found. The points are therefore referred to as keypoints. 16 | 17 | Usage 18 | ----- 19 | 20 | Keypoints are illustrated by circles of different colors. The radius of the circle illustrates the scale at which the keypoints are found, while the lines from the center to the border of the circle illustrate the dominant direction for rotation invariance. For the default program parameters, observe that SIFT finds prominent image features of different sizes, e.g., the right cheek with part of the nose (rose-colored circle) at a larger scale and several points along the edge of the hat at a smaller scale. 21 | 22 | Available actions 23 | ----------------- 24 | 25 | None 26 | 27 | Interactive parameters 28 | ---------------------- 29 | 30 | None 31 | 32 | Program parameters 33 | ------------------ 34 | 35 | * **Input image**: File path of the image to detect SIFT keypoints in. 36 | 37 | Hard-coded parameters 38 | --------------------- 39 | 40 | None 41 | 42 | Known issues 43 | ------------ 44 | 45 | None 46 | 47 | Missing features 48 | ---------------- 49 | 50 | None 51 | 52 | License 53 | ------- 54 | 55 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. -------------------------------------------------------------------------------- /features/sift_keypoints_test: -------------------------------------------------------------------------------- 1 | ../testdata/images/Lenna.png 2 | ../testdata/images/f001.png 3 | -------------------------------------------------------------------------------- /frequency_transforms/Makefile: -------------------------------------------------------------------------------- 1 | ORDER := dct_composition 2 | 3 | include ../common/appbase.mak 4 | -------------------------------------------------------------------------------- /frequency_transforms/dct_composition_readme.md: -------------------------------------------------------------------------------- 1 | 1-D DCT composition 2 | =================== 3 | 4 | **Short description**: Illustration of the signal composition through the 1-D IDCT (Illustrates a signal's composition by its 1-D DCT components) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Complete 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/dct_composition.png) 14 | 15 | The 1-D DCT is used to decompose discrete time-dependent signals (illustrated as a series of samples in the left part of the *Number of DCT components* window) into their frequency components. Conversely, these components can be used to reassemble the original signal. Using only a fraction of the components allows approximating the original signal. The amplitudes of the components are referred to as coefficients, which can be illustrated as series of samples in the frequency domain (right). 16 | 17 | Usage 18 | ----- 19 | 20 | Change the number of components (see parameters below) to be used for reassembling to see different approximations of the original signal. Observe that the first component represents the DC portion of the signal (purple on the left), while the second component represents the 0.5 Hz cosine wave portion (red). The amplitude of this wave is equal to the coefficient corresponding to 0.5 Hz (k = 1 on the right). The sum of the DC and 0.5 Hz components (left) adds up to the approximation that can be seen when increasing the number of components by one. Increasing the number of components up to the maximum, i.e., including all components, yields the original signal. 21 | 22 | ![Screenshot after displaying the first component](../screenshots/dct_composition_1.png) 23 | 24 | Available actions 25 | ----------------- 26 | 27 | None 28 | 29 | Interactive parameters 30 | ---------------------- 31 | 32 | * **Components** (track bar in the *Number of DCT components* window): Allows changing the number of DCT coefficients used to reconstruct the approximation of the original signal. 33 | 34 | Program parameters 35 | ------------------ 36 | 37 | None 38 | 39 | Hard-coded parameters 40 | --------------------- 41 | 42 | * `coefficients` (local to `ShowImage`): The DCT coefficients of the signal to be reassembled. *Note: The number of DCT coefficients must be 2 or larger.* 43 | 44 | Known issues 45 | ------------ 46 | 47 | None 48 | 49 | Missing features 50 | ---------------- 51 | 52 | None 53 | 54 | License 55 | ------- 56 | 57 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. -------------------------------------------------------------------------------- /frequency_transforms/dct_composition_test: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /fundamentals_of_stereoscopy/Makefile: -------------------------------------------------------------------------------- 1 | PARTS = 3d 2 | 3 | ORDER := epipolar_lines anaglyph 4 | 5 | include ../common/appbase.mak 6 | -------------------------------------------------------------------------------- /fundamentals_of_stereoscopy/anaglyph.cpp: -------------------------------------------------------------------------------- 1 | //Illustration of anaglyph images 2 | // Andreas Unterweger, 2017-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "combine.hpp" 12 | #include "window.hpp" 13 | #include "multiwin.hpp" 14 | 15 | static cv::Mat GetAnaglyphImage(const cv::Mat &left_image, const cv::Mat &right_image) 16 | { 17 | assert(left_image.size() == right_image.size()); 18 | assert(left_image.type() == CV_8UC1); 19 | assert(right_image.type() == CV_8UC1); 20 | 21 | const cv::Mat bgr_channels[3] { right_image, right_image, left_image }; //Set blue channel to right image and red channel to left image; set green channel to blue channel to not leave it empty 22 | cv::Mat anaglyph_image(left_image.size(), CV_8UC3); 23 | merge(bgr_channels, 3, anaglyph_image); 24 | return anaglyph_image; 25 | } 26 | 27 | static void ShowImages(const cv::Mat &left_image, const cv::Mat &right_image) 28 | { 29 | assert(left_image.size() == right_image.size()); 30 | constexpr auto image_window_name = "Left and right images"; 31 | imgutils::Window image_window(image_window_name); 32 | constexpr auto anaglyph_window_name = "Anaglyph image"; 33 | imgutils::Window anaglyph_window(anaglyph_window_name); 34 | const cv::Mat combined_image = imgutils::CombineImages({left_image, right_image}, imgutils::CombinationMode::Horizontal); 35 | image_window.UpdateContent(combined_image); 36 | const cv::Mat anaglyph_image = GetAnaglyphImage(left_image, right_image); 37 | anaglyph_window.UpdateContent(anaglyph_image); 38 | imgutils::MultiWindow all_windows({&image_window, &anaglyph_window}, imgutils::WindowAlignment::Horizontal); 39 | all_windows.ShowInteractive(); 40 | } 41 | 42 | int main(const int argc, const char * const argv[]) 43 | { 44 | if (argc != 3) 45 | { 46 | std::cout << "Illustrates stereoscopy with anaglyph images." << std::endl; 47 | std::cout << "Usage: " << argv[0] << " " << std::endl; 48 | return 1; 49 | } 50 | const auto left_image_filename = argv[1]; 51 | const cv::Mat left_image = cv::imread(left_image_filename, cv::IMREAD_GRAYSCALE); 52 | if (left_image.empty()) 53 | { 54 | std::cerr << "Could not read left image '" << left_image_filename << "'" << std::endl; 55 | return 2; 56 | } 57 | const auto right_image_filename = argv[2]; 58 | const cv::Mat right_image = cv::imread(right_image_filename, cv::IMREAD_GRAYSCALE); 59 | if (right_image.empty()) 60 | { 61 | std::cerr << "Could not read right image '" << right_image_filename << "'" << std::endl; 62 | return 3; 63 | } 64 | ShowImages(left_image, right_image); 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /fundamentals_of_stereoscopy/anaglyph_readme.md: -------------------------------------------------------------------------------- 1 | Anaglyph image 2 | ============== 3 | 4 | **Short description**: Illustration of anaglyph images (Illustrates stereoscopy with anaglyph images) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Complete 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/anaglyph.png) 14 | 15 | Anaglyph images can be created by coloring the left and right images of a stereoscopic image pair (window *Left and right images*) red and blue, respectively. The result is an R(G)B image (window *Anaglyph image*) which can be viewed with appropriate glasses that have red and cyan color filters for the left and right eye, respectively. 16 | 17 | Usage 18 | ----- 19 | 20 | The anaglyph image produces a 3-D effect when viewed with appropriate glasses. Observe that the distance of objects can be inferred without glasses from the anaglyph image due to the color differences. Objects which are close (high disparity) appear in both, red and cyan, next to one another, while object which are farther away (low disparity) only exhibit small additional red and cyan borders on each side or are all-grey due to the matching color channels. 21 | 22 | Available actions 23 | ----------------- 24 | 25 | None 26 | 27 | Interactive parameters 28 | ---------------------- 29 | 30 | None 31 | 32 | Program parameters 33 | ------------------ 34 | 35 | * **Left image**: File path of the left image of the stereoscopic image pair. 36 | * **Right image**: File path of the right image of the stereoscopic image pair. 37 | 38 | Hard-coded parameters 39 | --------------------- 40 | 41 | None 42 | 43 | Known issues 44 | ------------ 45 | 46 | None 47 | 48 | Missing features 49 | ---------------- 50 | 51 | None 52 | 53 | License 54 | ------- 55 | 56 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. -------------------------------------------------------------------------------- /fundamentals_of_stereoscopy/anaglyph_test: -------------------------------------------------------------------------------- 1 | ../testdata/images/im2.png ../testdata/images/im6.png 2 | -------------------------------------------------------------------------------- /fundamentals_of_stereoscopy/epipolar_lines_test: -------------------------------------------------------------------------------- 1 | ../testdata/3dmodels/bun_zipper.ply 2 | -------------------------------------------------------------------------------- /global_todos.txt: -------------------------------------------------------------------------------- 1 | Upgrade VTK to >= 9.2 so that Debian >= 12 can be used as the OS 2 | Specify common modules in Makefiles per executable instead of per folder/Makefile 3 | Create aliases for commonly used cv::Mat_ 8-bit image class and cv::Vec3b color class 4 | Isolate tractor from sample images for matching demonstrations (separate branch) 5 | -------------------------------------------------------------------------------- /image_compression/Makefile: -------------------------------------------------------------------------------- 1 | ORDER := csf rgb_mixer ycbcr_mixer rgb_vs_ycbcr chroma_subsampling dct_basis dct_decomposition jpeg_quality 2 | 3 | include ../common/appbase.mak 4 | -------------------------------------------------------------------------------- /image_compression/chroma_subsampling_readme.md: -------------------------------------------------------------------------------- 1 | Chrominance subsampling 2 | ======================= 3 | 4 | **Short description**: Illustration of chrominance subsampling (Illustrates the effect of chrominance subsampling) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Near-complete (nice-to-have features missing) 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/chroma_subsampling.png) 14 | 15 | Human visual perception is less sensitive to differences in color than it is to differences in brightness. Thus, the chrominance channels of an image (left in the *Chrominance subsampling* window) can be subsampled (right) without it being apparent to a human observer. The luminance channel remains untouched. 16 | 17 | Usage 18 | ----- 19 | 20 | Change the subsampling (see parameters below) to see changes to the output image. Omitting all chrominance information (4:0:0 subsampling) is clearly distinguishable from the original image, while other forms of subsampling are not, unless magnified signficantly, e.g. around strong borders between different colors. Observe that different subsamplings yield different storage sizes compared to the original image. This allows for saving storage space at practically no perceptual loss in quality. 21 | 22 | *Note: Since the conversion between RGB and YCbCr and back is only lossless up to rounding errors, single pixel value differences are possible even for 4:4:4 subsampling.* 23 | 24 | ![Screenshot with 4:4:4 subsampling](../screenshots/chroma_subsampling_444.png) 25 | 26 | Available actions 27 | ----------------- 28 | 29 | None. *Note: See below for parameters to change.* 30 | 31 | Interactive parameters 32 | ---------------------- 33 | 34 | * **Subsampling** (radio buttons): Allows switching between 4:4:4 (no subsampling), 4:2:0 (1-in-4 chrominance subsampling) and 4:0:0 subsampling (no chrominance channels). 35 | 36 | Program parameters 37 | ------------------ 38 | 39 | * **Input image**: File path of the image to subsample. 40 | 41 | Hard-coded parameters 42 | --------------------- 43 | 44 | None 45 | 46 | Known issues 47 | ------------ 48 | 49 | None 50 | 51 | Missing features 52 | ---------------- 53 | 54 | * **4:2:2 subsampling**: There is no option to illustrate the effect of 4:2:2 subsampling. If *OpenCV* adds 4:2:2 subsampling (see [*OpenCV* issue #9587](https://github.com/opencv/opencv/issues/9587)), this demonstration can be supplemented accordingly. 55 | 56 | Lincense 57 | -------- 58 | 59 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. -------------------------------------------------------------------------------- /image_compression/chroma_subsampling_test: -------------------------------------------------------------------------------- 1 | ../testdata/images/Lenna.png 2 | ../testdata/images/recttext.png 3 | -------------------------------------------------------------------------------- /image_compression/csf.cpp: -------------------------------------------------------------------------------- 1 | //Illustration of the contrast sensitivity function 2 | // Andreas Unterweger, 2017-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include "window.hpp" 11 | 12 | static double ExponentialProgression(const double minimum, const double maximum, const unsigned int steps, const unsigned int step) 13 | { 14 | assert(minimum < maximum); 15 | assert(steps > 0); 16 | assert(step <= steps); 17 | return minimum * pow(maximum / minimum, static_cast(step) / steps); 18 | } 19 | 20 | static cv::Mat GenerateCSFImage() 21 | { 22 | constexpr int width = 800; 23 | constexpr int height = 600; 24 | constexpr double max_brightness = 255; 25 | static_assert(max_brightness >= 0 && max_brightness <= 255, "Maximum brightness must fit into 8 bits (unsigned char)"); 26 | cv::Mat_ image(height, width, static_cast(max_brightness)); 27 | image.forEach([](unsigned char &value, const int position[]) 28 | { 29 | constexpr double min_frequency = 1; 30 | constexpr double max_frequency = width / 10; //TODO: width / 2 - 1 would be the Shannon limit; is there a sanity check for aliasing when frequency increases within one period? If width is too small, even the current value of 100 is too large 31 | constexpr double min_amplitude = 0.5; //Resolution limit (after rounding) 32 | constexpr double max_amplitude = static_cast(max_brightness) / 2; 33 | static_assert(min_amplitude < max_amplitude, "Minimum amplitude must be smaller than maximum amplitude"); 34 | constexpr double offset = max_brightness - max_amplitude; 35 | const int y = position[0]; 36 | const int x = position[1]; 37 | const double amplitude = ExponentialProgression(min_amplitude, max_amplitude, height, y + 1); 38 | const double phase = static_cast(x) / width; 39 | const double frequency = ExponentialProgression(min_frequency, max_frequency, width, x + 1); 40 | value = offset + amplitude * sin(2 * M_PI * phase * frequency); 41 | }); 42 | return image; 43 | } 44 | 45 | static void ShowContrastSensitivityFunction() 46 | { 47 | constexpr auto window_name = "Contrast sensitivity function"; 48 | const cv::Mat csf_image = GenerateCSFImage(); 49 | imgutils::Window window(window_name, csf_image); 50 | window.ShowInteractive(); 51 | } 52 | 53 | int main(const int argc, const char * const argv[]) 54 | { 55 | if (argc != 1) 56 | { 57 | std::cout << "Illustrates the contrast sensitivity function." << std::endl; 58 | std::cout << "Usage: " << argv[0] << std::endl; 59 | return 1; 60 | } 61 | ShowContrastSensitivityFunction(); 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /image_compression/csf_readme.md: -------------------------------------------------------------------------------- 1 | Contrast sensitivity function 2 | ============================= 3 | 4 | **Short description**: Illustration of the contrast sensitivity function (Illustrates the contrast sensitivity function) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Near-complete (nice-to-have features missing) 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/csf.png) 14 | 15 | The perception of contrast, i.e., the difference between the darkest and brightest values, depends on the spatial frequency. The frequency-dependent perceptual contrast limit varies from human to human and is referred to as the contrast sensitivity function. An individual's contrast sensitivity function can be visualized through a sinusodial pattern with increasing frequency and contrast (window *Contrast sensitivity function*). 16 | 17 | Usage 18 | ----- 19 | 20 | Observe that areas of low contrast (top) for very low (top left) and very high spatial frequencies appear entirely grey. The border between the grey areas and the visible sinusodial pattern is the contrast sensitivity function. 21 | 22 | Available actions 23 | ----------------- 24 | 25 | None 26 | 27 | Interactive parameters 28 | ---------------------- 29 | 30 | None 31 | 32 | Program parameters 33 | ------------------ 34 | 35 | None 36 | 37 | Hard-coded parameters 38 | --------------------- 39 | 40 | * `width` (local to `GenerateCSFImage`): Horizontal window size in pixels. 41 | * `height` (local to `GenerateCSFImage`): Vertical window size in pixels. 42 | * `max_brightness` (local to `GenerateCSFImage`): Brighest value displayed in the sinusodial pattern. The default is 255 (maximum possible 8-bit value). 43 | 44 | Known issues 45 | ------------ 46 | 47 | None 48 | 49 | Missing features 50 | ---------------- 51 | 52 | * **Correct maximum spatial frequency**: The Shannon limit for a signal with an exponentially increasing frequency is not trivial to determine. The maximum frequency must be below the Shannon limit to avoid aliasing patterns in the right part of the picture. 53 | 54 | Lincense 55 | -------- 56 | 57 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. -------------------------------------------------------------------------------- /image_compression/csf_test: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /image_compression/dct_basis.cpp: -------------------------------------------------------------------------------- 1 | //Illustration of 2-D DCT basis functions 2 | // Andreas Unterweger, 2016-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include "math.hpp" 11 | #include "imgmath.hpp" 12 | #include "combine.hpp" 13 | #include "window.hpp" 14 | 15 | static cv::Mat GenerateBasisFunctions(const size_t block_size, const size_t i) 16 | { 17 | std::vector basis_functions(block_size); 18 | for (size_t j = 0; j < block_size; j++) 19 | basis_functions[j] = imgutils::Get2DDCTBasisFunctionImage(block_size, i, j); 20 | return imgutils::CombineImages(block_size, basis_functions.data(), imgutils::CombinationMode::Horizontal, 1); 21 | } 22 | 23 | static cv::Mat GenerateBasisFunctions(const size_t block_size) 24 | { 25 | std::vector basis_function_rows(block_size); 26 | for (size_t i = 0; i < block_size; i++) 27 | basis_function_rows[i] = GenerateBasisFunctions(block_size, i); 28 | return imgutils::CombineImages(block_size, basis_function_rows.data(), imgutils::CombinationMode::Vertical, 1); 29 | } 30 | 31 | static void ShowBasisFunctions(const unsigned int block_size) 32 | { 33 | constexpr auto window_size = 500; 34 | const auto window_name = std::to_string(block_size) + "x" + std::to_string(block_size) + "-DCT basis functions"; 35 | const cv::Mat basis_functions = GenerateBasisFunctions(block_size); 36 | imgutils::Window window(window_name, basis_functions, cv::Size(window_size, window_size)); 37 | window.ShowInteractive(); 38 | } 39 | 40 | int main(const int argc, const char * const argv[]) 41 | { 42 | if (argc > 2) 43 | { 44 | std::cout << "Illustrates the basis functions of the 2-D-DCT." << std::endl; 45 | std::cout << "Usage: " << argv[0] << " [ = 8]" << std::endl; 46 | return 1; 47 | } 48 | unsigned int block_size = 8; 49 | if (argc == 2) 50 | { 51 | block_size = std::stoi(argv[1]); 52 | if (block_size < 1 || block_size > 32) 53 | { 54 | std::cerr << "DCT block size must be between 1 and 32" << std::endl; 55 | return 2; 56 | } 57 | } 58 | ShowBasisFunctions(block_size); 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /image_compression/dct_basis_readme.md: -------------------------------------------------------------------------------- 1 | 2-D DCT basis functions 2 | ======================= 3 | 4 | **Short description**: Illustration of 2-D DCT basis functions (Illustrates the basis functions of the 2-D-DCT) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Complete 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/dct_basis.png) 14 | 15 | The DCT is applied to blocks of image data (pixels) for various applications like compression. The two-dimensional basis functions (window *8x8-DCT basis functions*) depend on the block size and represent the components into which the 2-D pixel data is decomposed. 16 | 17 | Usage 18 | ----- 19 | 20 | Observe that the spatial frequency of the basis functions increases in both, the horizontal and vertical direction. The horizontal and vertical spatial frequencies are independent of one another. For the DC component (top-left-most basis function), the spatial frequency is 0. 21 | 22 | Available actions 23 | ----------------- 24 | 25 | None. *Note: See below for program parameters to change.* 26 | 27 | Interactive parameters 28 | ---------------------- 29 | 30 | None 31 | 32 | Program parameters 33 | ------------------ 34 | 35 | * **Block size** (optional, default 8): The transform size of the block in pixels. This value is identical to the number of basis functions in each direction (horizontal and vertical). 36 | 37 | Hard-coded parameters 38 | --------------------- 39 | 40 | * `window_size` (local to `ShowBasisFunctions`): Width and height of the window in pixels. 41 | 42 | Known issues 43 | ------------ 44 | 45 | None 46 | 47 | Missing features 48 | ---------------- 49 | 50 | None 51 | 52 | License 53 | ------- 54 | 55 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. -------------------------------------------------------------------------------- /image_compression/dct_basis_test: -------------------------------------------------------------------------------- 1 | 8 2 | -------------------------------------------------------------------------------- /image_compression/dct_decomposition_test: -------------------------------------------------------------------------------- 1 | ../testdata/images/Lenna.png 2 | -------------------------------------------------------------------------------- /image_compression/jpeg_quality_readme.md: -------------------------------------------------------------------------------- 1 | JPEG quality 2 | ============ 3 | 4 | **Short description**: Illustration of JPEG quality levels (Illustrates JPEG compression at different quality levels) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Near-complete (non-crucial bugs unfixed) 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/jpeg_quality.png) 14 | 15 | JPEG compression decreases the storage requirements for images at the expense of a number of artifacts due to quantization (window *Uncompressed vs. JPEG compressed*). The strength of the quantization, i.e., the frequency-dependent quantization step sizes, can be derived from a single quality parameter for convenience. The deviation of the compressed image (right) from the original image (left) can be visualized through a difference image (window *Difference*) and expressed by the PSNR value of the Y (luminance) channel. 16 | 17 | *Note on residual visualizations: Yellow pixels indicate positive differences, teal pixels indicate negative differences. The brighter the color is, the larger the differences are in absolute terms. Black equals zero, i.e., no difference.* 18 | 19 | Usage 20 | ----- 21 | 22 | Change the quality parameter (see parameters below) to see the storage size as well as the visibility and severity of the artifacts change. Observe that the differences between the input image and the compressed image are clearly visible for low quality values and yield low Y-PSNR values. 23 | 24 | ![Screenshot after setting the quality parameter to 1%](../screenshots/jpeg_quality_1.png) 25 | 26 | Available actions 27 | ----------------- 28 | 29 | None. *Note: See below for parameters to change.* 30 | 31 | Interactive parameters 32 | ---------------------- 33 | 34 | * **Quality** (track bar in the *Uncompressed vs. JPEG compressed* window): Allows changing the JPEG quality parameter used for compression in percent. 35 | 36 | Program parameters 37 | ------------------ 38 | 39 | * **Input image**: File path of the image to compress. 40 | 41 | Hard-coded parameters 42 | --------------------- 43 | 44 | None 45 | 46 | Known issues 47 | ------------ 48 | 49 | * **Window positioning**: The *Difference* window is positioned on the right, exceeding the maximum specified screen size for the default (test) image. It would better to position the *Difference* window under or above the compressed image. 50 | 51 | Missing features 52 | ---------------- 53 | 54 | None 55 | 56 | License 57 | ------- 58 | 59 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. -------------------------------------------------------------------------------- /image_compression/jpeg_quality_test: -------------------------------------------------------------------------------- 1 | ../testdata/images/recttext.png 2 | ../testdata/images/Lenna.png 3 | -------------------------------------------------------------------------------- /image_compression/rgb_mixer.cpp: -------------------------------------------------------------------------------- 1 | //Illustration of RGB color mixing 2 | // Andreas Unterweger, 2018-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include "common.hpp" 13 | #include "window.hpp" 14 | 15 | class RGB_data 16 | { 17 | protected: 18 | static constexpr char portion_names[] = { 'R', 'G', 'B' }; 19 | static constexpr const auto &first_portion_name = portion_names[0]; 20 | 21 | using TrackBarType = imgutils::TrackBar; 22 | std::unique_ptr portion_trackbars[comutils::arraysize(portion_names)]; 23 | 24 | imgutils::Window window; 25 | 26 | static cv::Mat GenerateColorImage(const cv::Vec3b &pixel_value) 27 | { 28 | constexpr auto image_dimension = 300; 29 | const cv::Size image_size(image_dimension, image_dimension); 30 | const cv::Mat image(image_size, CV_8UC3, pixel_value); 31 | return image; 32 | } 33 | 34 | static void UpdateImage(RGB_data &data) 35 | { 36 | unsigned char RGB_portions[comutils::arraysize(data.portion_names)]; //RGB portions from trackbar values 37 | std::transform(std::rbegin(data.portion_trackbars), std::rend(data.portion_trackbars), std::begin(RGB_portions), //BGR order (reverse iteration) 38 | [](const std::unique_ptr &portion_trackbar) 39 | { 40 | return static_cast(portion_trackbar->GetValue()); 41 | }); 42 | const cv::Vec3b pixel_value(RGB_portions); 43 | const cv::Mat image = GenerateColorImage(pixel_value); 44 | data.window.UpdateContent(image); 45 | } 46 | 47 | void AddTrackBars() 48 | { 49 | std::transform(std::begin(portion_names), std::end(portion_names), std::begin(portion_trackbars), 50 | [this](const char &portion_name) 51 | { 52 | using namespace std::string_literals; 53 | const auto trackbar_name = portion_name + " portion"s; 54 | const auto default_value = &portion_name == &first_portion_name ? 255 : 0; //Default red (R=255, G=0, B=0) 55 | return std::make_unique(trackbar_name, window, 255, 0, default_value, UpdateImage, *this); 56 | }); 57 | } 58 | 59 | 60 | static constexpr auto window_name = "RGB color mixer"; 61 | public: 62 | RGB_data() : window(window_name) 63 | { 64 | AddTrackBars(); 65 | UpdateImage(*this); //Update with default values 66 | } 67 | 68 | void ShowImage() 69 | { 70 | window.ShowInteractive(); 71 | } 72 | }; 73 | 74 | static void ShowImage() 75 | { 76 | RGB_data data; 77 | data.ShowImage(); 78 | } 79 | 80 | int main(const int argc, const char * const argv[]) 81 | { 82 | if (argc != 1) 83 | { 84 | std::cout << "Illustrates how RGB portions can be mixed into different colors." << std::endl; 85 | std::cout << "Usage: " << argv[0] << std::endl; 86 | return 1; 87 | } 88 | ShowImage(); 89 | return 0; 90 | } 91 | -------------------------------------------------------------------------------- /image_compression/rgb_mixer_readme.md: -------------------------------------------------------------------------------- 1 | RGB mixer 2 | ========= 3 | 4 | **Short description**: Illustration of RGB color mixing (Illustrates how RGB portions can be mixed into different colors) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Complete 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/rgb_mixer.png) 14 | 15 | Human color perception is based on the three primary colors red, green and blue. Practically any color (window *RGB color mixer*) can be mixed by adding these three components with corresponding per-component intensities. The set of all colors that can be produced through mixing is referred to as the RGB color space. *Note: The choice of the primary colors determines which colors can be mixed in the first place. Thus, not all visible colors can be mixed and displayed.* 16 | 17 | Usage 18 | ----- 19 | 20 | Change the portions of the components (see parameters below) to see the mixed color change. Observe that setting all but one component to zero yields a shade of the respective primary color, whereas setting R, G and B equal yields a shade of grey. 21 | 22 | ![Screenshot after mixing the color yellow](../screenshots/rgb_mixer_yellow.png) 23 | 24 | Available actions 25 | ----------------- 26 | 27 | None. *Note: See below for parameters to change.* 28 | 29 | Interactive parameters 30 | ---------------------- 31 | 32 | * **R portion** (track bar in the *RGB color mixer* window): Allows changing the intensity of the red component between none (0) and the maximum for 8-bit channels (255). 33 | * **G portion** (track bar in the *RGB color mixer* window): Allows changing the intensity of the green component between none (0) and the maximum for 8-bit channels (255). 34 | * **B portion** (track bar in the *RGB color mixer* window): Allows changing the intensity of the blue component between none (0) and the maximum for 8-bit channels (255). 35 | 36 | Program parameters 37 | ------------------ 38 | 39 | None 40 | 41 | Hard-coded parameters 42 | --------------------- 43 | 44 | * `image_dimension` (local to `RGB_data::GenerateColorImage`): Width and height of the displayed color (image) in pixels. 45 | 46 | Known issues 47 | ------------ 48 | 49 | None 50 | 51 | Missing features 52 | ---------------- 53 | 54 | None 55 | 56 | License 57 | ------- 58 | 59 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. -------------------------------------------------------------------------------- /image_compression/rgb_mixer_test: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /image_compression/rgb_vs_ycbcr.cpp: -------------------------------------------------------------------------------- 1 | //Illustration of RGB and YCbCr component decomposition 2 | // Andreas Unterweger, 2016-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "combine.hpp" 12 | #include "window.hpp" 13 | 14 | static void ShowImage(const cv::Mat &image) 15 | { 16 | constexpr auto window_name = "RGB vs. YCbCr"; 17 | cv::Mat bgr_planes[3]; 18 | cv::split(image, bgr_planes); 19 | cv::Mat ycrcb_image; 20 | cv::cvtColor(image, ycrcb_image, cv::COLOR_BGR2YCrCb); //TODO: Allow subsampling (how? cv::cvtColor makes a 1-channel matrix with cv::COLOR_BGR2YUV_*) 21 | cv::Mat ycrcb_planes[3]; 22 | cv::split(ycrcb_image, ycrcb_planes); 23 | const cv::Mat rgb_planes_combined = imgutils::CombineImages({image, bgr_planes[2], bgr_planes[1], bgr_planes[0]}, imgutils::CombinationMode::Horizontal); //BGR as RGB 24 | const cv::Mat ycbcr_planes_combined = imgutils::CombineImages({image, ycrcb_planes[0], ycrcb_planes[2], ycrcb_planes[1]}, imgutils::CombinationMode::Horizontal); //YCrCb as YCbCr 25 | cv::Mat combined_images = imgutils::CombineImages({rgb_planes_combined, ycbcr_planes_combined}, imgutils::CombinationMode::Vertical); 26 | cv::resize(combined_images, combined_images, cv::Size(), 1 / sqrt(2), 1 / sqrt(2), cv::INTER_LANCZOS4); //TODO: Don't resize, but find another way to fit the window(s) to the screen size, e.g., by allowing to hide the original image via a checkbox 27 | imgutils::Window window(window_name, combined_images); 28 | window.ShowInteractive(); 29 | } 30 | 31 | int main(const int argc, const char * const argv[]) 32 | { 33 | if (argc != 2) 34 | { 35 | std::cout << "Extracts the RGB and YCbCr channels of an image and displays them." << std::endl; 36 | std::cout << "Usage: " << argv[0] << " " << std::endl; 37 | return 1; 38 | } 39 | const auto image_filename = argv[1]; 40 | const cv::Mat image = cv::imread(image_filename); 41 | if (image.empty()) 42 | { 43 | std::cerr << "Could not read input image '" << image_filename << "'" << std::endl; 44 | return 2; 45 | } 46 | ShowImage(image); 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /image_compression/rgb_vs_ycbcr_readme.md: -------------------------------------------------------------------------------- 1 | RGB vs. YCbCr decomposition 2 | =========================== 3 | 4 | **Short description**: Illustration of RGB and YCbCr component decomposition (Extracts the RGB and YCbCr channels of an image and displays them) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Work in progress (internal bugs unfixed and nice-to-have features missing) 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/rgb_vs_ycbcr.png) 14 | 15 | A color image (left-most part of the *RGB vs. YCbCr* window) can be split into its R, G and B planes (top), i.e., each pixel can be broken down into its red, green and blue components. The image can also be split into its Y, Cb, Cr and planes (bottom) after converting it from the RGB color space to the YCbCr color space. 16 | 17 | Usage 18 | ----- 19 | 20 | Observe that the RGB channels correlate strongly and exhibit relatively high intensities, while the Cb and Cr channels do not correlate strongly with the Y channel and contain relatively low intensities. These properties make the YCbCr channels of most images more suitable for compression algorithms than the RGB channels. 21 | 22 | Available actions 23 | ----------------- 24 | 25 | None 26 | 27 | Interactive parameters 28 | ---------------------- 29 | 30 | None 31 | 32 | Program parameters 33 | ------------------ 34 | 35 | * **Input image**: File path of the image to decompose. 36 | 37 | Hard-coded parameters 38 | --------------------- 39 | 40 | None 41 | 42 | Known issues 43 | ------------ 44 | 45 | * **Additional resizing**: Due to the high number of channels, the width of the displayed window would be very large. The output is resized so that the window fits the screen, but this introduces undesirable small artifacts. 46 | 47 | Missing features 48 | ---------------- 49 | 50 | * **Subsampling**: The YCbCr components are not subsampled. There is no option to choose between different subsamplings. 51 | 52 | License 53 | ------- 54 | 55 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. -------------------------------------------------------------------------------- /image_compression/rgb_vs_ycbcr_test: -------------------------------------------------------------------------------- 1 | ../testdata/images/Lenna.png 2 | -------------------------------------------------------------------------------- /image_compression/ycbcr_mixer_readme.md: -------------------------------------------------------------------------------- 1 | YCbCr mixer 2 | =========== 3 | 4 | **Short description**: Illustration of YCbCr color mixing (Illustrates how YCbCr portions can be mixed into different colors) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Near-complete (nice-to-have features missing) 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/ycbcr_mixer.png) 14 | 15 | The YCbCr color space separates the luminance (Y channel) from the chrominance information (Cb and Cr channels). Since the Y, Cb and Cr intensities of a color (window *YCbCr color mixer*) can be converted into the corresponding R, G and B intensities, the corresponding RGB color can be mixed from the Y, Cb and Cr intensities. Due to the convertibility, the YCbCr color space can represent all colors of the RGB color space. 16 | 17 | Usage 18 | ----- 19 | 20 | Change the portions of the components (see parameters below) to see the mixed color change. Observe that varying Y only changes the luminance, while varying Cb or Cr only changes the chrominance. 21 | 22 | ![Screenshot after mixing the color grey](../screenshots/ycbcr_mixer_grey.png) 23 | 24 | Available actions 25 | ----------------- 26 | 27 | None. *Note: See below for parameters to change.* 28 | 29 | Interactive parameters 30 | ---------------------- 31 | 32 | * **Y portion** (track bar in the *YCbCr color mixer* window): Allows changing the intensity of the luminance component between none (0) and the maximum for 8-bit channels (255). 33 | * **Cb portion** (track bar in the *YCbCr color mixer* window): Allows changing the intensity of the Cb (difference to green) component between none (0) and the maximum for 8-bit channels (255). 34 | * **Cr portion** (track bar in the *YCbCr color mixer* window): Allows changing the intensity of the Cr (difference to red( component between none (0) and the maximum for 8-bit channels (255). 35 | 36 | Program parameters 37 | ------------------ 38 | 39 | None 40 | 41 | Hard-coded parameters 42 | --------------------- 43 | 44 | * `image_dimension` (local to `YCbCr_data::GenerateColorImage`): Width and height of the displayed color (image) in pixels. 45 | 46 | Known issues 47 | ------------ 48 | 49 | None. *Note: Theoretically, Cb and Cr can be both, positive and negative. However, in all practically relevant applications, they are offset so that they are only positive. This convention is relied upon in this demonstration.* 50 | 51 | Missing features 52 | ---------------- 53 | 54 | * **Range validation**: Not all combinations of Y, Cb and Cr intensities yield valid RGB values. Even though all practically relevant applications clip the result of YCbCr-to-RGB conversions in the way that this demonstration does, there is no indicator for the validity of the intensity values. 55 | 56 | License 57 | ------- 58 | 59 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. -------------------------------------------------------------------------------- /image_compression/ycbcr_mixer_test: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /object_detection/Makefile: -------------------------------------------------------------------------------- 1 | ORDER := haar_detection viola_jones resampling 2 | 3 | include ../common/appbase.mak 4 | -------------------------------------------------------------------------------- /object_detection/haar_detection_test: -------------------------------------------------------------------------------- 1 | ../testdata/images/Lenna.png 2 | -------------------------------------------------------------------------------- /object_detection/resampling_readme.md: -------------------------------------------------------------------------------- 1 | Image resampling 2 | ================ 3 | 4 | **Short description**: Illustration of downsampling and upsampling (Illustrates the effect of resampling) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Near-complete (non-crucial bugs unfixed) 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/resampling.png) 14 | 15 | Resizing an image (left in the *Original vs. resampled (incl. intermediate downsampled)* window) requires resampling it. Reducing the image size is equivalent to downsampling with interpolation (right). Increasing the size is equivalent to upsampling with interpolation. The performance of different interpolation methods can be assessed by upsampling the downsampled image again to its original size and comparing this upsampled image (middle) to the original image (left). 16 | 17 | Usage 18 | ----- 19 | 20 | Change the interpolation method (see parameters below) to see the image fidelity and artifacts change. Observe that very small scaling factors, e.g., 5%, yield low fidelity regardless of the interpolation method due to information being lost during downsampling. However, differences between the interpolation methods are still clearly visible. 21 | 22 | ![Screenshot after setting the interpolation to bilinear at 5% of the size](../screenshots/resampling_5pc_bilinear.png) 23 | 24 | Available actions 25 | ----------------- 26 | 27 | None. *Note: See below for parameters to change.* 28 | 29 | Interactive parameters 30 | ---------------------- 31 | 32 | * **Interpolation method** (radio buttons): Allows switching between different interpolation methods (nearest-neighbor interpolation, bilinear interpolation and Lanczos interpolation with four neighbors in each direction). The selected interpolation method is used for both, upsampling and downsampling. 33 | * **Scaling** (track bar in the *Original vs. resampled (incl. intermediate downsampled)* window): Allows changing the size of the downscaled image relative to the original size in percent. 34 | 35 | Program parameters 36 | ------------------ 37 | 38 | * **Input image**: File path of the image to resample. 39 | 40 | Hard-coded parameters 41 | --------------------- 42 | 43 | None 44 | 45 | Known issues 46 | ------------ 47 | 48 | * **Window too large**: The window is slightly wider than 1050 pixels for the default input image. *Note: Using a smaller image or higher screen resolutions works around this issue.* 49 | 50 | Missing features 51 | ---------------- 52 | 53 | None 54 | 55 | License 56 | ------- 57 | 58 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. -------------------------------------------------------------------------------- /object_detection/resampling_test: -------------------------------------------------------------------------------- 1 | ../testdata/images/recttext.png 2 | ../testdata/images/Lenna.png 3 | -------------------------------------------------------------------------------- /object_detection/viola_jones_readme.md: -------------------------------------------------------------------------------- 1 | Object detection by Viola & Jones 2 | ================================= 3 | 4 | **Short description**: Illustration of Viola-Jones object detection (Illustrates object detection on video frames with the object detector by Viola and Jones) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Complete 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/viola_jones.png) 14 | 15 | The object detection algorithm by Viola and Jones can be used to find the position (red rectangle) of faces in an image (window *Image with objects to detect*), given an appropriately trained classifier cascade. This concept can be extended to detect faces in videos, i.e., sequences of images, when one frame is processed after another. 16 | 17 | Usage 18 | ----- 19 | 20 | Advance to the next frame (see parameters below) to its face detection results. For the default program parameters, observe that the detection is successful and relatively consistent among all frames. Observe that non-frontal faces are not detected or detected unreliably. 21 | 22 | ![Screenshot when using a different sequence with non-frontal faces](../screenshots/viola_jones_ice.png) 23 | 24 | Available actions 25 | ----------------- 26 | 27 | Press Q to quit. Use any other key to advance to the next frame. *Notes: Pressing any key in the last frame terminates the program.* 28 | 29 | Interactive parameters 30 | ---------------------- 31 | 32 | None 33 | 34 | Program parameters 35 | ------------------ 36 | 37 | * **Input video**: File path of the video to detect objects in. If *-* is specified, a webcam is used. *Note: An image or image sequence can also be specified instead of a video file.* 38 | * (optional) **Waiting time between frames**: Time in ms to wait after each processed frame. The default value 0 denotes infinite waiting, which can be interrupted by a key press. 39 | 40 | Hard-coded parameters 41 | --------------------- 42 | 43 | * `classifier_path` (local to `InitClassifier`): File path of the XML file specifying the classifier cascade to be used. 44 | * `line_width` (local to `HighlightFaces`): Width of the face-highlighting rectangles' lines in pixels. 45 | 46 | Known issues 47 | ------------ 48 | 49 | None 50 | 51 | Missing features 52 | ---------------- 53 | 54 | None 55 | 56 | License 57 | ------- 58 | 59 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. 60 | -------------------------------------------------------------------------------- /object_detection/viola_jones_test: -------------------------------------------------------------------------------- 1 | ../testdata/images/f%3d.png 2 | ../testdata/images/00%d.png 3 | - 1 4 | -------------------------------------------------------------------------------- /screenshots/anaglyph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/anaglyph.png -------------------------------------------------------------------------------- /screenshots/checkerboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/checkerboard.png -------------------------------------------------------------------------------- /screenshots/chroma_subsampling.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/chroma_subsampling.png -------------------------------------------------------------------------------- /screenshots/chroma_subsampling_444.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/chroma_subsampling_444.png -------------------------------------------------------------------------------- /screenshots/csf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/csf.png -------------------------------------------------------------------------------- /screenshots/dct_basis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/dct_basis.png -------------------------------------------------------------------------------- /screenshots/dct_composition.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/dct_composition.png -------------------------------------------------------------------------------- /screenshots/dct_composition_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/dct_composition_1.png -------------------------------------------------------------------------------- /screenshots/dct_decomposition.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/dct_decomposition.png -------------------------------------------------------------------------------- /screenshots/dct_decomposition_5_animated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/dct_decomposition_5_animated.png -------------------------------------------------------------------------------- /screenshots/dct_decomposition_5_during_animation.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/dct_decomposition_5_during_animation.webp -------------------------------------------------------------------------------- /screenshots/difference_of_gaussians.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/difference_of_gaussians.png -------------------------------------------------------------------------------- /screenshots/difference_of_gaussians_k4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/difference_of_gaussians_k4.png -------------------------------------------------------------------------------- /screenshots/distortion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/distortion.png -------------------------------------------------------------------------------- /screenshots/distortion_negative_p1_p2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/distortion_negative_p1_p2.png -------------------------------------------------------------------------------- /screenshots/epipolar_lines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/epipolar_lines.png -------------------------------------------------------------------------------- /screenshots/epipolar_lines_eye.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/epipolar_lines_eye.png -------------------------------------------------------------------------------- /screenshots/extrinsics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/extrinsics.png -------------------------------------------------------------------------------- /screenshots/extrinsics_negative_z_translation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/extrinsics_negative_z_translation.png -------------------------------------------------------------------------------- /screenshots/frequency_sensitivity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/frequency_sensitivity.png -------------------------------------------------------------------------------- /screenshots/frequency_sensitivity_50_mute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/frequency_sensitivity_50_mute.png -------------------------------------------------------------------------------- /screenshots/gaussian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/gaussian.png -------------------------------------------------------------------------------- /screenshots/gaussian_sigma5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/gaussian_sigma5.png -------------------------------------------------------------------------------- /screenshots/haar_detection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/haar_detection.png -------------------------------------------------------------------------------- /screenshots/haar_detection_eyes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/haar_detection_eyes.png -------------------------------------------------------------------------------- /screenshots/histogram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/histogram.png -------------------------------------------------------------------------------- /screenshots/histogram_64_bins.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/histogram_64_bins.png -------------------------------------------------------------------------------- /screenshots/homography.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/homography.png -------------------------------------------------------------------------------- /screenshots/homography_after_warping.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/homography_after_warping.png -------------------------------------------------------------------------------- /screenshots/howto_animation.txt: -------------------------------------------------------------------------------- 1 | The animated dct_decomposition_5_during_animation.webp can be created like this (coordinates for Debian 10 with Xfce): 2 | ffmpeg -f x11grab -video_size 1233x316 -framerate 10 -i :0.0+0,27 test%06d.png 3 | ffmpeg -y -i test%06d.png -ss 2 -vf fps=1 -lossless 1 -loop 5 dct_decomposition_animated.webp #where ss is set to the time period it took to start the animation 4 | -------------------------------------------------------------------------------- /screenshots/intra_prediction.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/intra_prediction.png -------------------------------------------------------------------------------- /screenshots/intra_prediction_horizontal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/intra_prediction_horizontal.png -------------------------------------------------------------------------------- /screenshots/intrinsics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/intrinsics.png -------------------------------------------------------------------------------- /screenshots/intrinsics_fx600_cx250.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/intrinsics_fx600_cx250.png -------------------------------------------------------------------------------- /screenshots/jpeg_quality.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/jpeg_quality.png -------------------------------------------------------------------------------- /screenshots/jpeg_quality_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/jpeg_quality_1.png -------------------------------------------------------------------------------- /screenshots/masking.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/masking.png -------------------------------------------------------------------------------- /screenshots/masking_100_0_mute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/masking_100_0_mute.png -------------------------------------------------------------------------------- /screenshots/matching_perspective.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/matching_perspective.png -------------------------------------------------------------------------------- /screenshots/matching_perspective_tractor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/matching_perspective_tractor.png -------------------------------------------------------------------------------- /screenshots/mean_feature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/mean_feature.png -------------------------------------------------------------------------------- /screenshots/mean_feature_zoomed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/mean_feature_zoomed.png -------------------------------------------------------------------------------- /screenshots/missing.txt: -------------------------------------------------------------------------------- 1 | If this folder is empty, please fetch the screenshots from https://github.com/dustsigns/lecture-demos/tree/master/screenshots. 2 | -------------------------------------------------------------------------------- /screenshots/motion_estimation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/motion_estimation.png -------------------------------------------------------------------------------- /screenshots/motion_estimation_perform_costmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/motion_estimation_perform_costmap.png -------------------------------------------------------------------------------- /screenshots/panoramic_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/panoramic_image.png -------------------------------------------------------------------------------- /screenshots/quantization.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/quantization.png -------------------------------------------------------------------------------- /screenshots/quantization_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/quantization_8.png -------------------------------------------------------------------------------- /screenshots/reconstruct3d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/reconstruct3d.png -------------------------------------------------------------------------------- /screenshots/reconstruct3d_zoomed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/reconstruct3d_zoomed.png -------------------------------------------------------------------------------- /screenshots/reflection2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/reflection2d.png -------------------------------------------------------------------------------- /screenshots/reflection2d_90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/reflection2d_90.png -------------------------------------------------------------------------------- /screenshots/reflection3d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/reflection3d.png -------------------------------------------------------------------------------- /screenshots/reflection3d_xz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/reflection3d_xz.png -------------------------------------------------------------------------------- /screenshots/resampling.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/resampling.png -------------------------------------------------------------------------------- /screenshots/resampling_5pc_bilinear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/resampling_5pc_bilinear.png -------------------------------------------------------------------------------- /screenshots/rgb_mixer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/rgb_mixer.png -------------------------------------------------------------------------------- /screenshots/rgb_mixer_yellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/rgb_mixer_yellow.png -------------------------------------------------------------------------------- /screenshots/rgb_vs_ycbcr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/rgb_vs_ycbcr.png -------------------------------------------------------------------------------- /screenshots/rotation2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/rotation2d.png -------------------------------------------------------------------------------- /screenshots/rotation2d_135.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/rotation2d_135.png -------------------------------------------------------------------------------- /screenshots/rotation3d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/rotation3d.png -------------------------------------------------------------------------------- /screenshots/rotation3d_x180_y90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/rotation3d_x180_y90.png -------------------------------------------------------------------------------- /screenshots/scaling2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/scaling2d.png -------------------------------------------------------------------------------- /screenshots/scaling2d_200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/scaling2d_200.png -------------------------------------------------------------------------------- /screenshots/scaling3d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/scaling3d.png -------------------------------------------------------------------------------- /screenshots/scaling3d_x50_y200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/scaling3d_x50_y200.png -------------------------------------------------------------------------------- /screenshots/semiglobal_matching.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/semiglobal_matching.png -------------------------------------------------------------------------------- /screenshots/sift_keypoint_matching.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/sift_keypoint_matching.png -------------------------------------------------------------------------------- /screenshots/sift_keypoint_matching_point92.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/sift_keypoint_matching_point92.png -------------------------------------------------------------------------------- /screenshots/sift_keypoints.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/sift_keypoints.png -------------------------------------------------------------------------------- /screenshots/translation2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/translation2d.png -------------------------------------------------------------------------------- /screenshots/translation2d_x20_y-30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/translation2d_x20_y-30.png -------------------------------------------------------------------------------- /screenshots/translation3d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/translation3d.png -------------------------------------------------------------------------------- /screenshots/translation3d_x-10_z20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/translation3d_x-10_z20.png -------------------------------------------------------------------------------- /screenshots/viola_jones.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/viola_jones.png -------------------------------------------------------------------------------- /screenshots/viola_jones_ice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/viola_jones_ice.png -------------------------------------------------------------------------------- /screenshots/ycbcr_mixer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/ycbcr_mixer.png -------------------------------------------------------------------------------- /screenshots/ycbcr_mixer_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/screenshots/ycbcr_mixer_grey.png -------------------------------------------------------------------------------- /stereo_matching/Makefile: -------------------------------------------------------------------------------- 1 | PARTS = 3d 2 | 3 | ORDER := semiglobal_matching checkerboard homography reconstruct3d 4 | 5 | include ../common/appbase.mak 6 | -------------------------------------------------------------------------------- /stereo_matching/checkerboard.cpp: -------------------------------------------------------------------------------- 1 | //Illustration of a checkerboard pattern for calibration 2 | // Andreas Unterweger, 2017-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include "window.hpp" 11 | 12 | static cv::Mat GenerateCheckerboardPattern(const unsigned int checkerboard_width, const unsigned int checkerboard_height) 13 | { 14 | constexpr auto field_size = 60U; 15 | static_assert(field_size != 0, "The size of a checkerboard field cannot be zero."); 16 | 17 | constexpr auto black = 0U; 18 | constexpr auto white = 255U; 19 | 20 | cv::Mat checkerboard(checkerboard_height * field_size, checkerboard_width * field_size, CV_8UC1, cv::Scalar(black)); //Color whole board black 21 | for (unsigned int y = 0; y < checkerboard_height; y++) 22 | { 23 | for (unsigned int x = 0; x < checkerboard_width; x++) 24 | { 25 | if ((x ^ y) & 1) //Color every other field white 26 | { 27 | const cv::Rect field_pixels(x * field_size, y * field_size, field_size, field_size); 28 | checkerboard(field_pixels).setTo(white); 29 | } 30 | } 31 | } 32 | return checkerboard; 33 | } 34 | 35 | static void ShowCheckerboard() 36 | { 37 | constexpr auto checkerboard_width = 10U; 38 | constexpr auto checkerboard_height = 7U; 39 | static_assert(checkerboard_width > 0 && checkerboard_height > 0, "The size of the checkerboard cannot be zero."); 40 | static_assert(checkerboard_width != checkerboard_height, "The checkerboard needs to be asymmetric."); 41 | 42 | const auto window_name = std::to_string(checkerboard_width) + "x" + std::to_string(checkerboard_height) + " checkerboard"; 43 | const cv::Mat checkerboard_pattern = GenerateCheckerboardPattern(checkerboard_width, checkerboard_height); 44 | imgutils::Window window(window_name, checkerboard_pattern); 45 | window.ShowInteractive(); 46 | } 47 | 48 | int main(const int argc, const char * const argv[]) 49 | { 50 | if (argc != 1) 51 | { 52 | std::cout << "Illustrates an asymmetrical checkerboard pattern for camera calibration." << std::endl; 53 | std::cout << "Usage: " << argv[0] << std::endl; 54 | return 1; 55 | } 56 | ShowCheckerboard(); 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /stereo_matching/checkerboard_readme.md: -------------------------------------------------------------------------------- 1 | 2-D checkerboard calibration pattern 2 | ==================================== 3 | 4 | **Short description**: Illustration of a checkerboard pattern for calibration (Illustrates an asymmetrical checkerboard pattern for camera calibration) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Complete 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/checkerboard.png) 14 | 15 | Camera calibration requires an object with known geometry. Checkerboard patterns (window *10x7 checkerboard*) can be used as two-dimensional [camera calibration patterns](https://docs.opencv.org/4.6.0/d4/d94/tutorial_camera_calibration.html). 16 | 17 | Usage 18 | ----- 19 | 20 | Observe that the checkerboard is asymmetric, i.e., the number of rows is different from the number of columns and the top and bottom fields on the left and right have different colors. This allows distinguishing rotations of the pattern without ambiguity. 21 | 22 | Available actions 23 | ----------------- 24 | 25 | None 26 | 27 | Interactive parameters 28 | ---------------------- 29 | 30 | None 31 | 32 | Program parameters 33 | ------------------ 34 | 35 | None 36 | 37 | Hard-coded parameters 38 | --------------------- 39 | 40 | * `field_size` (local to `GenerateCheckerboardPattern`): Horizontal and vertical size of each checkerboard field in pixels. 41 | * `checkerboard_width` (local to `ShowCheckerboard`): Number of horizontal checkerboard fields. 42 | * `checkerboard_height` (local to `ShowCheckerboard`): Number of vertical checkerboard fields. 43 | 44 | Known issues 45 | ------------ 46 | 47 | None 48 | 49 | Missing features 50 | ---------------- 51 | 52 | None 53 | 54 | License 55 | ------- 56 | 57 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. -------------------------------------------------------------------------------- /stereo_matching/checkerboard_test: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /stereo_matching/homography_readme.md: -------------------------------------------------------------------------------- 1 | Homography 2 | ========== 3 | 4 | **Short description**: Illustration of plane-to-plane warping with a homography (Illustrates the warp in perspective from one plane to another) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Work in progress (features missing) 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/homography.png) 14 | 15 | Homographies allow mapping 2-D surfaces to 2-D surfaces. They can be used to warp an image (window *Source image*) into a quadrangular region in another image (window *Target image*). This can be used for overlays. 16 | 17 | Usage 18 | ----- 19 | 20 | Set the corner points (see parameters below) to see the warped image within the defined quadrangle. Observe that the selected region is overlaid with the warped image fittingly if both contain approximately two-dimensional conent. 21 | 22 | ![Screenshot after warping](../screenshots/homography_after_warping.png) 23 | 24 | Available actions 25 | ----------------- 26 | 27 | * **Clear selection** (button): Deletes all previously specified corner points of the quadrangle and removes the warped image from the *Target image* window, if it has been warped. 28 | 29 | Interactive parameters 30 | ---------------------- 31 | 32 | * **Corner points** (left mouse click in the *Target image* window): Allows setting the position of a corner point of the quadrangle to warp the source image into. A total of four corner points need to be specified in the following order: Top-left, top-right, bottom-right, bottom-left. After setting the fourth position, the image is warped into the quadrangle specified by the four corner points. *Note: Clicking after warping, i.e., after the fourth position has been specified, does not do anything.* 33 | 34 | Program parameters 35 | ------------------ 36 | 37 | * **Source image**: File path of the image to warp. 38 | * **Target image**: File path of the image to warp the *source image* into. 39 | 40 | Hard-coded parameters 41 | --------------------- 42 | 43 | None 44 | 45 | Known issues 46 | ------------ 47 | 48 | None 49 | 50 | Missing features 51 | ---------------- 52 | 53 | * **Intuitive point selection**: The selection of corner points is unintuitive and needs to be explained. Changing the position of single points is not possible, but requires removing all points and starting over. 54 | 55 | License 56 | ------- 57 | 58 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. -------------------------------------------------------------------------------- /stereo_matching/homography_test: -------------------------------------------------------------------------------- 1 | ../testdata/images/Lenna.png ../testdata/images/news.png 2 | -------------------------------------------------------------------------------- /stereo_matching/reconstruct3d.cpp: -------------------------------------------------------------------------------- 1 | //Illustration of 3-D reconstruction from a disparity image 2 | // Andreas Unterweger, 2017-2022 3 | //This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "vizwin.hpp" 14 | 15 | static void FilterDepthImage(cv::Mat &depth_image) 16 | { 17 | const auto filter_threshold = depth_image.rows; 18 | constexpr auto NaN = std::numeric_limits::quiet_NaN(); 19 | const cv::Vec3f NaN_pixel = cv::Vec3f(NaN); 20 | 21 | auto filtered_depth_image = static_cast>(depth_image); 22 | std::replace_if(filtered_depth_image.begin(), filtered_depth_image.end(), 23 | [&filter_threshold](const auto &pixel) 24 | { 25 | return pixel[2] > filter_threshold; 26 | }, NaN_pixel); 27 | } 28 | 29 | static cv::Mat DisparityImageTo3D(const cv::Mat &disparity_image) 30 | { 31 | const auto Q = cv::Mat::eye(4, 4, CV_64FC1); //Use identity matrix as Q for simplicity (z coordinate = 1 / disparity) 32 | cv::Mat depth_image; 33 | cv::reprojectImageTo3D(disparity_image, depth_image, Q, true); 34 | FilterDepthImage(depth_image); 35 | return depth_image; 36 | } 37 | 38 | static void ShowWindow(const cv::Mat &disparity_image, const cv::Mat &left_image) 39 | { 40 | constexpr auto window_name = "3-D reconstruction"; 41 | vizutils::VisualizationWindow window(window_name); 42 | const cv::Mat depth_image = DisparityImageTo3D(disparity_image); 43 | cv::viz::WCloud reconstruction(depth_image, left_image); 44 | window.AddWidget("Point cloud", &reconstruction); 45 | window.ShowInteractive([&window]() 46 | { 47 | //TODO: Why does zooming no longer work once the pose is read and set again (even without changes) 48 | /*auto pose = window.GetViewerPose(); 49 | pose = pose.rotate(cv::Vec3f(M_PI, 0, 0)); //Flip camera around so that it faces into the right direction 50 | window.SetViewerPose(pose);*/ 51 | }); 52 | } 53 | 54 | int main(const int argc, const char * const argv[]) 55 | { 56 | if (argc != 3) 57 | { 58 | std::cout << "Illustrates 3-D reconstruction from an image and its disparity image." << std::endl; 59 | std::cout << "Usage: " << argv[0] << " " << std::endl; 60 | return 1; 61 | } 62 | const auto left_image_path = argv[1]; 63 | const cv::Mat left_image = cv::imread(left_image_path); 64 | if (left_image.empty()) 65 | { 66 | std::cerr << "Could not read left image '" << left_image_path << "'" << std::endl; 67 | return 2; 68 | } 69 | const auto disparity_image_path = argv[2]; 70 | const cv::Mat disparity_image = cv::imread(disparity_image_path, cv::IMREAD_GRAYSCALE); 71 | if (disparity_image.empty()) 72 | { 73 | std::cerr << "Could not read disparity image '" << disparity_image_path << "'" << std::endl; 74 | return 3; 75 | } 76 | ShowWindow(disparity_image, left_image); 77 | return 0; 78 | } 79 | -------------------------------------------------------------------------------- /stereo_matching/reconstruct3d_readme.md: -------------------------------------------------------------------------------- 1 | 3-D reconstruction 2 | ================== 3 | 4 | **Short description**: Illustration of 3-D reconstruction from a disparity image (Illustrates 3-D reconstruction from an image and its disparity image) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Near-complete (external bugs unfixed) 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/reconstruct3d.png) 14 | 15 | A disparity image can be converted into a depth image. Using the values of the depth image as Z coordinates allows reprojecting a (2-D) image pixel by pixel to achieve a 3-D reconstruction (window *3-D reconstruction*). 16 | 17 | Usage 18 | ----- 19 | 20 | Zoom into the reconstruction to see the single reprojected points (pixels). Move the camera to change the perspective. Observe that near and far-away objects in the image can be clearly distinguished due to the depth information. 21 | 22 | ![Screenshot after zooming in](../screenshots/reconstruct3d_zoomed.png) 23 | 24 | Available actions 25 | ----------------- 26 | 27 | None 28 | 29 | Interactive parameters 30 | ---------------------- 31 | 32 | None. *Note: The camera position and zoom can be changed using the mouse.* 33 | 34 | Program parameters 35 | ------------------ 36 | 37 | * **Input image**: File path of the image to be reprojected. 38 | * **Disparity image**: File path of the disparity image corresponding to the *input image*. 39 | 40 | Hard-coded parameters 41 | --------------------- 42 | 43 | None 44 | 45 | Known issues 46 | ------------ 47 | 48 | None 49 | 50 | Missing features 51 | ---------------- 52 | 53 | * **Correct camera orientation**: The reprojection appears upside down. It must be flipped. *Note: Code to fix this exists, but is commented as applying it disables zooming due to an *OpenCV* bug (see [*OpenCV* issue #9575](https://github.com/opencv/opencv/issues/9575)).* 54 | 55 | License 56 | ------- 57 | 58 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. 59 | -------------------------------------------------------------------------------- /stereo_matching/reconstruct3d_test: -------------------------------------------------------------------------------- 1 | ../testdata/images/im2.png ../testdata/images/disp2.png 2 | -------------------------------------------------------------------------------- /stereo_matching/semiglobal_matching_readme.md: -------------------------------------------------------------------------------- 1 | Semi-global stereo matching 2 | =========================== 3 | 4 | **Short description**: Illustration of semi-global stereo matching (Illustrates the estimation of a disparity image via semi-global stereo matching) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Complete 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/semiglobal_matching.png) 14 | 15 | The difference in position of a pixel between the left and the right image of a stereoscopic image pair is referred to as disparity. A disparity image (window *Estimated disparity image*), i.e., a map of disparity values for each pixel, can be estimated from a pair of left and right images (window *Left and right images*) using the semi-global stereo matching algorithm. 16 | 17 | Usage 18 | ----- 19 | 20 | For the default program parameters, observe that the disparity of large objects can be estimated relatively well, while small objects and the regions between objects have either no or incorrectly estimated disparity information. 21 | 22 | Available actions 23 | ----------------- 24 | 25 | None 26 | 27 | Interactive parameters 28 | ---------------------- 29 | 30 | None 31 | 32 | Program parameters 33 | ------------------ 34 | 35 | * **Left image**: File path of the left image to be used as input for the semi-global stereo matching algorithm. 36 | * **Right image**: File path of the right image to be used as input for the semi-global stereo matching algorithm. 37 | 38 | Hard-coded parameters 39 | --------------------- 40 | 41 | * `number_of_disparities`: The number of different disparity values for the semi-global stereo matching algorithm. 42 | * `SAD_window_size` (local to `GetDisparityImage`): The window size in pixels used for calculating the quality of a match in the semi-global stereo matching algorithm. 43 | 44 | Known issues 45 | ------------ 46 | 47 | None 48 | 49 | Missing features 50 | ---------------- 51 | 52 | None 53 | 54 | License 55 | ------- 56 | 57 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. -------------------------------------------------------------------------------- /stereo_matching/semiglobal_matching_test: -------------------------------------------------------------------------------- 1 | ../testdata/images/im2.png ../testdata/images/im6.png 2 | -------------------------------------------------------------------------------- /testdata/3dmodels/sources.txt: -------------------------------------------------------------------------------- 1 | bun_zipper: Execute in bash 2 | wget 'http://graphics.stanford.edu/pub/3Dscanrep/bunny.tar.gz' && tar xfz bunny.tar.gz && mv bunny/reconstruction/bun_zipper.ply . && rm -f bunny.tar.gz && rm -rf bunny 3 | -------------------------------------------------------------------------------- /testdata/images/001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/001.png -------------------------------------------------------------------------------- /testdata/images/002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/002.png -------------------------------------------------------------------------------- /testdata/images/Lenna.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/Lenna.png -------------------------------------------------------------------------------- /testdata/images/disp2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/disp2.png -------------------------------------------------------------------------------- /testdata/images/f001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/f001.png -------------------------------------------------------------------------------- /testdata/images/f002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/f002.png -------------------------------------------------------------------------------- /testdata/images/f003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/f003.png -------------------------------------------------------------------------------- /testdata/images/f004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/f004.png -------------------------------------------------------------------------------- /testdata/images/f005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/f005.png -------------------------------------------------------------------------------- /testdata/images/f006.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/f006.png -------------------------------------------------------------------------------- /testdata/images/f007.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/f007.png -------------------------------------------------------------------------------- /testdata/images/f008.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/f008.png -------------------------------------------------------------------------------- /testdata/images/f009.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/f009.png -------------------------------------------------------------------------------- /testdata/images/f010.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/f010.png -------------------------------------------------------------------------------- /testdata/images/im2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/im2.png -------------------------------------------------------------------------------- /testdata/images/im6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/im6.png -------------------------------------------------------------------------------- /testdata/images/news.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/news.png -------------------------------------------------------------------------------- /testdata/images/pan001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/pan001.png -------------------------------------------------------------------------------- /testdata/images/pan002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/pan002.png -------------------------------------------------------------------------------- /testdata/images/pan003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/pan003.png -------------------------------------------------------------------------------- /testdata/images/pan004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/pan004.png -------------------------------------------------------------------------------- /testdata/images/pan005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/pan005.png -------------------------------------------------------------------------------- /testdata/images/pan006.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/pan006.png -------------------------------------------------------------------------------- /testdata/images/pan007.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/pan007.png -------------------------------------------------------------------------------- /testdata/images/recttext.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/recttext.png -------------------------------------------------------------------------------- /testdata/images/sources.txt: -------------------------------------------------------------------------------- 1 | Lenna: https://en.wikipedia.org/wiki/File:Lenna.png 2 | 001, 002: Execute in bash (with ffmpeg installed) 3 | wget 'ftp://ftp.tnt.uni-hannover.de/pub/svc/testsequences/ICE_352x288_30_orig_02_yuv.zip' && unzip ICE_352x288_30_orig_02_yuv.zip && ffmpeg -y -s 352x288 -r 30 -i ICE_352x288_30_orig_02_yuv/ICE_352x288_30_orig_02.yuv -ss 0:00:05 -frames 2 -q 0 %03d.png && rm -f ICE_352x288_30_orig_02_yuv.zip && rm -rf ICE_352x288_30_orig_02_yuv 4 | f001-f010: Execute in bash (with ffmpeg installed) 5 | wget 'ftp://ftp.tnt.uni-hannover.de/pub/svc/testsequences/FOREMAN_352x288_30_orig_01_yuv.zip' && unzip FOREMAN_352x288_30_orig_01_yuv.zip && ffmpeg -y -s 352x288 -r 30 -i FOREMAN_352x288_30_orig_01.yuv -ss 0:00:01 -frames 10 -q 0 f%03d.png && rm -f FOREMAN_352x288_30_orig_01.yuv FOREMAN_352x288_30_orig_01_yuv.zip 6 | t001-t014: Execute in bash (with ffmpeg installed) 7 | wget 'https://media.xiph.org/video/derf/y4m/tractor_1080p25.y4m' && ffmpeg -y -i tractor_1080p25.y4m -vf framestep=50,scale=480:270 -q 0 t%03d.png && rm -f tractor_1080p25.y4m 8 | tractor: Execute in bash (with ImageMagick installed and t004 already present) 9 | convert t004.png -crop 300x200+0+50 +repage tractor.png 10 | pan001-pan007: Execute in bash (with ffmpeg installed) 11 | wget 'ftp://vqeg.its.bldrdoc.gov/MM/7-12_testclip/7-12_testclip_CIF.avi' && ffmpeg -y -i 7-12_testclip_CIF.avi -ss 74 -frames 7 -vf framestep=50 -q 0 pan%03d.png && rm -f 7-12_testclip_CIF.avi 12 | im2, im6 disp2: Execute in bash 13 | wget 'http://vision.middlebury.edu/stereo/data/scenes2003/newdata/cones/cones-png-2.zip' && unzip cones-png-2.zip && mv cones/im2.png cones/im6.png cones/disp2.png . && rm -f cones-png-2.zip && rm -rf cones 14 | news: Execute in bash (with p7zip and ffmpeg installed) 15 | wget 'http://trace.eas.asu.edu/yuv/news/news_cif.7z' && 7zr x news_cif.7z && ffmpeg -y -s 352x288 -r 30 -i news_cif.yuv -frames 1 -q 0 news.png && rm -f news_cif.7z news_cif.yuv 16 | recttext: Execute in bash (with ImageMagick installed) 17 | rm -f recttext.png && convert -size 600x400 xc:white -stroke 'gray(20%)' -fill 'gray(20%)' -font "Times-Roman" -pointsize 70 -gravity center -draw "text 0,0 'Längerer großer Text'" -pointsize 20 -draw "text 150,150 'Kleiner Text'" -stroke black -fill black -draw "line 25,25 150,150" -fill red -stroke red -draw "rectangle 400,10 500,110" -fill blue -stroke blue -draw "circle 450,60 475,85" recttext.png 18 | -------------------------------------------------------------------------------- /testdata/images/t001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/t001.png -------------------------------------------------------------------------------- /testdata/images/t002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/t002.png -------------------------------------------------------------------------------- /testdata/images/t003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/t003.png -------------------------------------------------------------------------------- /testdata/images/t004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/t004.png -------------------------------------------------------------------------------- /testdata/images/t005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/t005.png -------------------------------------------------------------------------------- /testdata/images/t006.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/t006.png -------------------------------------------------------------------------------- /testdata/images/t007.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/t007.png -------------------------------------------------------------------------------- /testdata/images/t008.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/t008.png -------------------------------------------------------------------------------- /testdata/images/t009.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/t009.png -------------------------------------------------------------------------------- /testdata/images/t010.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/t010.png -------------------------------------------------------------------------------- /testdata/images/t011.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/t011.png -------------------------------------------------------------------------------- /testdata/images/t012.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/t012.png -------------------------------------------------------------------------------- /testdata/images/t013.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/t013.png -------------------------------------------------------------------------------- /testdata/images/t014.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/t014.png -------------------------------------------------------------------------------- /testdata/images/tractor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustsigns/lecture-demos/e40583521027125a1c4208be84faeb3d1b9ea6dc/testdata/images/tractor.png -------------------------------------------------------------------------------- /todo.sh: -------------------------------------------------------------------------------- 1 | #Utility to list all TODOs in sources, headers, scripts and Makefiles 2 | # Andreas Unterweger, 2017-2022 3 | #This code is licensed under the 3-Clause BSD License. See LICENSE file for details. 4 | 5 | echo "To-dos in source and header files:" 6 | find . -iname '*.[ch]pp' -print -o -iname '*.h' -print | xargs grep -o --line-number --color=always -e '/[/*]TODO: .*' | sed 's/\/[/*]TODO: \(.*\)/\1/' | sed 's/\*\/$//' | tee >(wc -l) & 7 | wait $! 8 | echo "To-dos in script and Make files:" 9 | find . -iname 'Makefile' -print -o -iname '*.mak' -print -o -iname '*.sh' -print | grep -v ./todo.sh | xargs grep -o --line-number --color=always -e '#TODO: .*' | sed 's/#TODO: \(.*\)/\1/' | tee >(wc -l) & 10 | wait $! 11 | echo "Global to-dos:" 12 | cat global_todos.txt | tee >(wc -l) & 13 | wait $! 14 | -------------------------------------------------------------------------------- /video_compression/Makefile: -------------------------------------------------------------------------------- 1 | ORDER := motion_estimation intra_prediction 2 | 3 | include ../common/appbase.mak 4 | -------------------------------------------------------------------------------- /video_compression/intra_prediction_readme.md: -------------------------------------------------------------------------------- 1 | Intra prediction 2 | ================ 3 | 4 | **Short description**: Illustration of intra prediction and the effect of residuals on transforms (Illustrates intra prediction and its effect on the subsequent transform) 5 | 6 | **Author**: Andreas Unterweger 7 | 8 | **Status**: Near-complete (nice-to-have features missing) 9 | 10 | Overview 11 | -------- 12 | 13 | ![Screenshot](../screenshots/intra_prediction.png) 14 | 15 | In order to code a block of an image, its pixels can either be transformed by themselves (window *Original and its DCT*) or as the difference to a prediction (window *Residual and its DCT*). This prediction is based on information from coded neighboring blocks (windows *Predicted* and *Prediction illustration*) and impacts the residual. The properties of the transformed residual (window *Residual and its DCT*) relevant for coding differ from the properties of the stand-alone transformed pixels (window *Original and its DCT*). 16 | 17 | *Note on residual visualizations: Yellow pixels indicate positive differences, teal pixels indicate negative differences. The brighter the color is, the larger the differences are in absolute terms. Black equals zero, i.e., no difference.* 18 | 19 | Usage 20 | ----- 21 | 22 | Change the prediction method (see parameters below) to see the different performance of horizontal and vertical intra prediction, respectively. For the default program parameters, vertical prediction yields a lower sum of absolute transformed differences (SATD) and a larger number of small coefficients than horizontal prediction. Observe that the number of small coefficients is larger for the stand-alone block than it is for the residuals with any prediction method. 23 | 24 | ![Screenshot with horizontal prediction](../screenshots/intra_prediction_horizontal.png) 25 | 26 | Available actions 27 | ----------------- 28 | 29 | None. *Note: See below for parameters to change.* 30 | 31 | Interactive parameters 32 | ---------------------- 33 | 34 | * **Prediction method** (radio buttons): Allows switching between horizontal intra prediction (from the bottom-left block) and vertical intra prediction (from the top-right block). 35 | 36 | Program parameters 37 | ------------------ 38 | 39 | * **Input image**: File path of the image to perform intra prediction in. *Note: Only the center region of the image is used for prediction.* 40 | 41 | Hard-coded parameters 42 | --------------------- 43 | 44 | * `block_size` (local to `prediction_data`): x and y dimension of the block to be predicted. *Note: The displayed area consists of four blocks, i.e., its x and y dimensions are double that of `block_size`, each.* 45 | 46 | Known issues 47 | ------------ 48 | 49 | None 50 | 51 | Missing features 52 | ---------------- 53 | 54 | * **Border illustration**: There is no option to illustrate the four separate blocks in the original image, e.g., by their borders. 55 | 56 | License 57 | ------- 58 | 59 | This demonstration and its documentation (this document) are provided under the 3-Clause BSD License (see [`LICENSE`](../LICENSE) file in the parent folder for details). Please provide appropriate attribution if you use any part of this demonstration or its documentation. 60 | -------------------------------------------------------------------------------- /video_compression/intra_prediction_test: -------------------------------------------------------------------------------- 1 | ../testdata/images/Lenna.png 2 | -------------------------------------------------------------------------------- /video_compression/motion_estimation_test: -------------------------------------------------------------------------------- 1 | ../testdata/images/001.png ../testdata/images/002.png 328 136 2 | ../testdata/images/001.png ../testdata/images/002.png 188 96 3 | ../testdata/images/001.png ../testdata/images/002.png 64 140 4 | --------------------------------------------------------------------------------