Test color conversion.
#include <visp3/core/vpConfig.h>
#if defined(VISP_HAVE_CATCH2)
#define CATCH_CONFIG_RUNNER
#include "common.hpp"
#include <catch.hpp>
#include <visp3/core/vpImageConvert.h>
#include <visp3/core/vpIoTools.h>
#include <visp3/core/vpEndian.h>
#include <visp3/io/vpImageIo.h>
#ifdef ENABLE_VISP_NAMESPACE
#endif
static const double maxMeanPixelError = 1.5;
static const unsigned int width = 223, height = 151;
TEST_CASE("Gray to RGBa conversion", "[image_conversion]")
{
SECTION("Image 1x16 (SSE41 aligned=true)")
{
unsigned int h = 1, w = 16;
common_tools::fill(gray);
common_tools::grayToRGBaRef(gray.
bitmap,
reinterpret_cast<unsigned char *
>(rgba_ref.
bitmap), gray.
getSize());
CHECK((rgba == rgba_ref));
}
SECTION("Image 1x17 (SSE41 aligned=false)")
{
unsigned int h = 1, w = 17;
common_tools::fill(gray);
common_tools::grayToRGBaRef(gray.
bitmap,
reinterpret_cast<unsigned char *
>(rgba_ref.
bitmap), gray.
getSize());
CHECK((rgba == rgba_ref));
}
SECTION("Image 1x32 (AVX2 aligned=true)")
{
unsigned int h = 1, w = 32;
common_tools::fill(gray);
common_tools::grayToRGBaRef(gray.
bitmap,
reinterpret_cast<unsigned char *
>(rgba_ref.
bitmap), gray.
getSize());
CHECK((rgba == rgba_ref));
}
SECTION("Image 1x33 (AVX2 aligned=false)")
{
unsigned int h = 1, w = 33;
common_tools::fill(gray);
common_tools::grayToRGBaRef(gray.
bitmap,
reinterpret_cast<unsigned char *
>(rgba_ref.
bitmap), gray.
getSize());
CHECK((rgba == rgba_ref));
}
SECTION("Image 4x64 (general aligned = true")
{
unsigned int h = 4, w = 64;
common_tools::fill(gray);
common_tools::grayToRGBaRef(gray.
bitmap,
reinterpret_cast<unsigned char *
>(rgba_ref.
bitmap), gray.
getSize());
CHECK((rgba == rgba_ref));
}
SECTION("Image 5x65 (general aligned = false")
{
unsigned int h = 5, w = 65;
common_tools::fill(gray);
common_tools::grayToRGBaRef(gray.
bitmap,
reinterpret_cast<unsigned char *
>(rgba_ref.
bitmap), gray.
getSize());
CHECK((rgba == rgba_ref));
}
}
TEST_CASE("RGBa to Gray conversion", "[image_conversion]")
{
SECTION("Image 1x16 (SSE41 aligned=true)")
{
unsigned int h = 1, w = 16;
common_tools::fill(rgba);
common_tools::RGBaToGrayRef(reinterpret_cast<unsigned char *>(rgba.bitmap), gray_ref.bitmap, rgba.getSize());
double error = 0;
CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
std::cout << "RGBa to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
SECTION("Image 1x17 (SSE41 aligned=false)")
{
unsigned int h = 1, w = 17;
common_tools::fill(rgba);
common_tools::RGBaToGrayRef(reinterpret_cast<unsigned char *>(rgba.bitmap), gray_ref.bitmap, rgba.getSize());
double error = 0;
CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
std::cout << "RGBa to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
SECTION("Image 1x32 (AVX2 aligned=true)")
{
unsigned int h = 1, w = 32;
common_tools::fill(rgba);
common_tools::RGBaToGrayRef(reinterpret_cast<unsigned char *>(rgba.bitmap), gray_ref.bitmap, rgba.getSize());
double error = 0;
CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
std::cout << "RGBa to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
SECTION("Image 1x33 (AVX2 aligned=false)")
{
unsigned int h = 1, w = 33;
common_tools::fill(rgba);
common_tools::RGBaToGrayRef(reinterpret_cast<unsigned char *>(rgba.bitmap), gray_ref.bitmap, rgba.getSize());
double error = 0;
CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
std::cout << "RGBa to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
SECTION("Image 4x64 (general aligned = true")
{
unsigned int h = 4, w = 64;
common_tools::fill(rgba);
common_tools::RGBaToGrayRef(reinterpret_cast<unsigned char *>(rgba.bitmap), gray_ref.bitmap, rgba.getSize());
double error = 0;
CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
std::cout << "RGBa to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
SECTION("Image 5x65 (general aligned = false")
{
unsigned int h = 5, w = 65;
common_tools::fill(rgba);
common_tools::RGBaToGrayRef(reinterpret_cast<unsigned char *>(rgba.bitmap), gray_ref.bitmap, rgba.getSize());
double error = 0;
CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
std::cout << "RGBa to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
}
TEST_CASE("RGB to Gray conversion", "[image_conversion]")
{
SECTION("Image 1x16 (SSE41 aligned=true)")
{
unsigned int h = 1, w = 16;
std::vector<unsigned char> rgb(h * w * 3);
common_tools::fill(rgb);
common_tools::RGBToGrayRef(rgb.data(), gray_ref.bitmap, gray_ref.getWidth(), gray_ref.getHeight(), false);
double error = 0;
CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
std::cout << "RGB to Gray conversion 1, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
CHECK(common_tools::almostEqual(gray_ref, gray2, maxMeanPixelError, error));
std::cout << "RGB to Gray conversion 2, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
SECTION("Image 1x17 (SSE41 aligned=false)")
{
unsigned int h = 1, w = 17;
std::vector<unsigned char> rgb(h * w * 3);
common_tools::fill(rgb);
common_tools::RGBToGrayRef(rgb.data(), gray_ref.bitmap, gray_ref.getWidth(), gray_ref.getHeight(), false);
double error = 0;
CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
std::cout << "RGB to Gray conversion 1, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
CHECK(common_tools::almostEqual(gray_ref, gray2, maxMeanPixelError, error));
std::cout << "RGB to Gray conversion 2, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
SECTION("Image 1x32 (AVX2 aligned=true)")
{
unsigned int h = 1, w = 32;
std::vector<unsigned char> rgb(h * w * 3);
common_tools::fill(rgb);
common_tools::RGBToGrayRef(rgb.data(), gray_ref.bitmap, gray_ref.getWidth(), gray_ref.getHeight(), false);
double error = 0;
CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
std::cout << "RGB to Gray conversion 1, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
CHECK(common_tools::almostEqual(gray_ref, gray2, maxMeanPixelError, error));
std::cout << "RGB to Gray conversion 2, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
SECTION("Image 1x33 (AVX2 aligned=false)")
{
unsigned int h = 1, w = 33;
std::vector<unsigned char> rgb(h * w * 3);
common_tools::fill(rgb);
common_tools::RGBToGrayRef(rgb.data(), gray_ref.bitmap, gray_ref.getWidth(), gray_ref.getHeight(), false);
double error = 0;
CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
std::cout << "RGB to Gray conversion 1, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
CHECK(common_tools::almostEqual(gray_ref, gray2, maxMeanPixelError, error));
std::cout << "RGB to Gray conversion 2, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
SECTION("Image 4x64 (general aligned = true")
{
unsigned int h = 4, w = 64;
std::vector<unsigned char> rgb(h * w * 3);
common_tools::fill(rgb);
common_tools::RGBToGrayRef(rgb.data(), gray_ref.bitmap, gray_ref.getWidth(), gray_ref.getHeight(), false);
double error = 0;
CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
std::cout << "RGB to Gray conversion 1, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
CHECK(common_tools::almostEqual(gray_ref, gray2, maxMeanPixelError, error));
std::cout << "RGB to Gray conversion 2, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
SECTION("Image 5x65 (general aligned = false")
{
unsigned int h = 5, w = 65;
std::vector<unsigned char> rgb(h * w * 3);
common_tools::fill(rgb);
common_tools::RGBToGrayRef(rgb.data(), gray_ref.bitmap, gray_ref.getWidth(), gray_ref.getHeight(), false);
double error = 0;
CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
std::cout << "RGB to Gray conversion 1, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
CHECK(common_tools::almostEqual(gray_ref, gray2, maxMeanPixelError, error));
std::cout << "RGB to Gray conversion 2, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
}
TEST_CASE("RGB <==> RGBa conversion", "[image_conversion]")
{
SECTION("Image 1x16 (SSE41 aligned=true)")
{
unsigned int h = 1, w = 16;
common_tools::fill(rgba_ref);
std::vector<unsigned char> rgb(h * w * 3);
CHECK((rgba == rgba_ref));
}
SECTION("Image 1x17 (SSE41 aligned=false)")
{
unsigned int h = 1, w = 17;
common_tools::fill(rgba_ref);
std::vector<unsigned char> rgb(h * w * 3);
CHECK((rgba == rgba_ref));
}
SECTION("Image 1x32 (AVX2 aligned=true)")
{
unsigned int h = 1, w = 32;
common_tools::fill(rgba_ref);
std::vector<unsigned char> rgb(h * w * 3);
CHECK((rgba == rgba_ref));
}
SECTION("Image 1x33 (AVX2 aligned=false)")
{
unsigned int h = 1, w = 33;
common_tools::fill(rgba_ref);
std::vector<unsigned char> rgb(h * w * 3);
CHECK((rgba == rgba_ref));
}
SECTION("Image 4x64 (general aligned = true")
{
unsigned int h = 4, w = 64;
common_tools::fill(rgba_ref);
std::vector<unsigned char> rgb(h * w * 3);
CHECK((rgba == rgba_ref));
}
SECTION("Image 5x65 (general aligned = false")
{
unsigned int h = 5, w = 65;
common_tools::fill(rgba_ref);
std::vector<unsigned char> rgb(h * w * 3);
CHECK((rgba == rgba_ref));
}
}
TEST_CASE("BGR to Gray conversion", "[image_conversion]")
{
SECTION("Image 1x16 (SSE41 aligned=true)")
{
unsigned int h = 1, w = 16;
common_tools::fill(rgba_ref);
std::vector<unsigned char> bgr;
common_tools::RGBaToBGR(rgba_ref, bgr);
double error = 0;
CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
std::cout << "BGR to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
SECTION("Image 1x17 (SSE41 aligned=false)")
{
unsigned int h = 1, w = 17;
common_tools::fill(rgba_ref);
std::vector<unsigned char> bgr;
common_tools::RGBaToBGR(rgba_ref, bgr);
double error = 0;
CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
std::cout << "BGR to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
SECTION("Image 1x32 (AVX2 aligned=true)")
{
unsigned int h = 1, w = 32;
common_tools::fill(rgba_ref);
std::vector<unsigned char> bgr;
common_tools::RGBaToBGR(rgba_ref, bgr);
double error = 0;
CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
std::cout << "BGR to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
SECTION("Image 1x33 (AVX2 aligned=false)")
{
unsigned int h = 1, w = 33;
common_tools::fill(rgba_ref);
std::vector<unsigned char> bgr;
common_tools::RGBaToBGR(rgba_ref, bgr);
double error = 0;
CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
std::cout << "BGR to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
SECTION("Image 4x64 (general aligned = true")
{
unsigned int h = 4, w = 64;
common_tools::fill(rgba_ref);
std::vector<unsigned char> bgr;
common_tools::RGBaToBGR(rgba_ref, bgr);
double error = 0;
CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
std::cout << "BGR to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
SECTION("Image 5x65 (general aligned = false")
{
unsigned int h = 5, w = 65;
common_tools::fill(rgba_ref);
std::vector<unsigned char> bgr;
common_tools::RGBaToBGR(rgba_ref, bgr);
double error = 0;
CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
std::cout << "BGR to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
}
TEST_CASE("BGRa to Gray conversion", "[image_conversion]")
{
SECTION("Image 1x16 (SSE41 aligned=true)")
{
unsigned int h = 1, w = 16;
common_tools::fill(rgba_ref);
std::vector<unsigned char> bgra;
common_tools::RGBaToBGRa(rgba_ref, bgra);
double error = 0;
CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
std::cout << "BGRa to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
SECTION("Image 1x17 (SSE41 aligned=false)")
{
unsigned int h = 1, w = 17;
common_tools::fill(rgba_ref);
std::vector<unsigned char> bgra;
common_tools::RGBaToBGRa(rgba_ref, bgra);
double error = 0;
CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
std::cout << "BGRa to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
SECTION("Image 1x32 (AVX2 aligned=true)")
{
unsigned int h = 1, w = 32;
common_tools::fill(rgba_ref);
std::vector<unsigned char> bgra;
common_tools::RGBaToBGRa(rgba_ref, bgra);
double error = 0;
CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
std::cout << "BGRa to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
SECTION("Image 1x33 (AVX2 aligned=false)")
{
unsigned int h = 1, w = 33;
common_tools::fill(rgba_ref);
std::vector<unsigned char> bgra;
common_tools::RGBaToBGRa(rgba_ref, bgra);
double error = 0;
CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
std::cout << "BGRa to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
SECTION("Image 4x64 (general aligned = true")
{
unsigned int h = 4, w = 64;
common_tools::fill(rgba_ref);
std::vector<unsigned char> bgra;
common_tools::RGBaToBGRa(rgba_ref, bgra);
double error = 0;
CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
std::cout << "BGRa to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
SECTION("Image 5x65 (general aligned = false")
{
unsigned int h = 5, w = 65;
common_tools::fill(rgba_ref);
std::vector<unsigned char> bgra;
common_tools::RGBaToBGRa(rgba_ref, bgra);
double error = 0;
CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
std::cout << "BGRa to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
}
TEST_CASE("BGRa to RGBa conversion", "[image_conversion]")
{
SECTION("Image 1x16 (SSE41 aligned=true)")
{
unsigned int h = 1, w = 16;
common_tools::fill(rgba_ref);
std::vector<unsigned char> bgra_ref;
common_tools::RGBaToBGRa(rgba_ref, bgra_ref);
rgba.getHeight());
double error = 0;
CHECK(common_tools::almostEqual(rgba_ref, rgba, maxMeanPixelError, error));
std::cout << "BGRa to RGBa conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
SECTION("Image 1x17 (SSE41 aligned=false)")
{
unsigned int h = 1, w = 17;
common_tools::fill(rgba_ref);
std::vector<unsigned char> bgra_ref;
common_tools::RGBaToBGRa(rgba_ref, bgra_ref);
rgba.getHeight());
double error = 0;
CHECK(common_tools::almostEqual(rgba_ref, rgba, maxMeanPixelError, error));
std::cout << "BGRa to RGBa conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
SECTION("Image 1x32 (AVX2 aligned=true)")
{
unsigned int h = 1, w = 32;
common_tools::fill(rgba_ref);
std::vector<unsigned char> bgra_ref;
common_tools::RGBaToBGRa(rgba_ref, bgra_ref);
rgba.getHeight());
double error = 0;
CHECK(common_tools::almostEqual(rgba_ref, rgba, maxMeanPixelError, error));
std::cout << "BGRa to RGBa conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
SECTION("Image 1x33 (AVX2 aligned=false)")
{
unsigned int h = 1, w = 33;
common_tools::fill(rgba_ref);
std::vector<unsigned char> bgra_ref;
common_tools::RGBaToBGRa(rgba_ref, bgra_ref);
rgba.getHeight());
double error = 0;
CHECK(common_tools::almostEqual(rgba_ref, rgba, maxMeanPixelError, error));
std::cout << "BGRa to RGBa conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
SECTION("Image 4x64 (general aligned = true")
{
unsigned int h = 4, w = 64;
common_tools::fill(rgba_ref);
std::vector<unsigned char> bgra_ref;
common_tools::RGBaToBGRa(rgba_ref, bgra_ref);
rgba.getHeight());
double error = 0;
CHECK(common_tools::almostEqual(rgba_ref, rgba, maxMeanPixelError, error));
std::cout << "BGRa to RGBa conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
SECTION("Image 5x65 (general aligned = false")
{
unsigned int h = 5, w = 65;
common_tools::fill(rgba_ref);
std::vector<unsigned char> bgra_ref;
common_tools::RGBaToBGRa(rgba_ref, bgra_ref);
rgba.getHeight());
double error = 0;
CHECK(common_tools::almostEqual(rgba_ref, rgba, maxMeanPixelError, error));
std::cout << "BGRa to RGBa conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
}
TEST_CASE("Split <==> Merge conversion", "[image_conversion]")
{
common_tools::fill(rgba_ref);
CHECK((rgba == rgba_ref));
}
#if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
TEST_CASE("OpenCV Mat <==> vpImage conversion", "[image_conversion]")
{
SECTION("CV_8UC3 to vpRGBa")
{
cv::Mat img(height, width, CV_8UC3);
common_tools::fill(img);
common_tools::BGRToRGBaRef(img.data, reinterpret_cast<unsigned char *>(rgba_ref.bitmap), img.cols, img.rows, false);
CHECK((rgba_ref == rgba));
}
SECTION("CV_8UC1 to vpRGBa")
{
cv::Mat img(height, width, CV_8UC1);
common_tools::fill(img);
common_tools::grayToRGBaRef(img.data, reinterpret_cast<unsigned char *>(rgba_ref.bitmap), height * width);
CHECK((rgba_ref == rgba));
}
SECTION("CV_8UC3 to unsigned char")
{
cv::Mat img(height, width, CV_8UC3);
common_tools::fill(img);
common_tools::BGRToGrayRef(img.data, gray_ref.
bitmap, img.cols, img.rows,
false);
double error = 0;
CHECK(common_tools::almostEqual(gray_ref, gray, maxMeanPixelError, error));
std::cout << "BGR to Gray conversion, mean error: " << error << " max allowed: " << maxMeanPixelError << std::endl;
}
SECTION("CV_8UC1 to unsigned char")
{
cv::Mat img(height, width, CV_8UC1);
common_tools::fill(img);
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++) {
REQUIRE(img.at<uchar>(i, j) == gray[i][j]);
}
}
}
SECTION("CV_16UC1 to uint16_t")
{
unsigned int w = 3, h = 3;
cv::Mat img = (cv::Mat_<uint16_t>(h, w) << 65, 650, 6500, 65000, 60000, 6000, 600, 60, 6);
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++) {
REQUIRE(img.at<uint16_t>(i, j) == gray16[i][j]);
}
}
cv::Mat img_col1 = img.col(1);
for (int i = 0; i < img_col1.rows; i++) {
for (int j = 0; j < img_col1.cols; j++) {
REQUIRE(img_col1.at<uint16_t>(i, j) == gray16_col1[i][j]);
}
}
}
}
#endif
#if (VISP_HAVE_DATASET_VERSION >= 0x030500)
{
for (
unsigned int i = 0; i < I_Bayer_8U.
getHeight(); i++) {
for (
unsigned int j = 0; j < I_Bayer_8U.
getWidth(); j++) {
I_Bayer_8U[i][j] = buffer[j * I_Bayer_8U.
getHeight() + i];
}
}
}
static void col2im(
const std::vector<uint16_t> &buffer,
vpImage<uint16_t> &I_Bayer_16U)
{
for (
unsigned int i = 0; i < I_Bayer_16U.
getHeight(); i++) {
for (
unsigned int j = 0; j < I_Bayer_16U.
getWidth(); j++) {
I_Bayer_16U[i][j] = buffer[j * I_Bayer_16U.
getHeight() + i];
}
}
}
{
for (
unsigned int i = 0; i < I_RGBA_8U.
getHeight(); i++) {
for (
unsigned int j = 0; j < I_RGBA_8U.
getWidth(); j++) {
vpMath::saturate<unsigned char>(I_RGBA_16U[0][(i * I_RGBA_8U.
getWidth() + j) * 4 + 0] / (
float)divisor),
vpMath::saturate<unsigned char>(I_RGBA_16U[0][(i * I_RGBA_8U.
getWidth() + j) * 4 + 1] / (
float)divisor),
vpMath::saturate<unsigned char>(I_RGBA_16U[0][(i * I_RGBA_8U.
getWidth() + j) * 4 + 2] / (
float)divisor));
}
}
}
{
double mse = 0;
for (
unsigned int i = 0; i < I_RGBA_8U.
getHeight(); i++) {
for (
unsigned int j = 0; j < I_RGBA_8U.
getWidth(); j++) {
vpColVector err = I_RGBA_8U[i][j] - I_RGBA_8U_ref[i][j];
}
}
return 10 * std::log10(255 * 255 / mse);
}
static bool readBinaryFile(const std::string &filename, std::vector<uint16_t> &buffer)
{
std::FILE *f = std::fopen(filename.c_str(), "rb");
CHECK(f != nullptr);
if (f == nullptr) {
return false;
}
size_t sread = std::fread(&buffer[0], sizeof buffer[0], buffer.size(), f);
REQUIRE(sread == buffer.size());
#ifdef VISP_BIG_ENDIAN
std::vector<uint16_t> tmp = buffer;
for (size_t i = 0; i < tmp.size(); i++) {
}
#endif
std::fclose(f);
return true;
}
static bool readBinaryFile(const std::string &filename, std::vector<uint8_t> &buffer)
{
std::FILE *f = std::fopen(filename.c_str(), "rb");
CHECK(f != nullptr);
if (f == nullptr) {
return false;
}
size_t sread = std::fread(&buffer[0], sizeof buffer[0], buffer.size(), f);
REQUIRE(sread == buffer.size());
std::fclose(f);
return true;
}
TEST_CASE("Bayer conversion", "[image_conversion]")
{
const double min_PSNR_bilinear = 21, min_PSNR_Malvar = 24;
SECTION("16-bit")
{
std::vector<uint16_t> buffer(height * width);
SECTION("BGGR")
{
const std::string filename =
if (readBinaryFile(filename, buffer)) {
col2im(buffer, I_Bayer_16U);
SECTION("Bilinear")
{
convertTo(I_RGBA_16U, I_RGBA_8U);
double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
std::cout << "16-bit - BGGR - Bilinear - PSNR: " << PSNR << " min required: " << min_PSNR_bilinear << std::endl;
CHECK(PSNR >= min_PSNR_bilinear);
}
SECTION("Malvar")
{
convertTo(I_RGBA_16U, I_RGBA_8U);
double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
std::cout << "16-bit - BGGR - Malvar - PSNR: " << PSNR << " min required: " << min_PSNR_Malvar << std::endl;
CHECK(PSNR >= min_PSNR_Malvar);
}
}
}
SECTION("GBRG")
{
const std::string filename =
if (readBinaryFile(filename, buffer)) {
col2im(buffer, I_Bayer_16U);
SECTION("Bilinear")
{
convertTo(I_RGBA_16U, I_RGBA_8U);
double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
std::cout << "16-bit - GBRG - Bilinear - PSNR: " << PSNR << " min required: " << min_PSNR_bilinear << std::endl;
CHECK(PSNR >= min_PSNR_bilinear);
}
SECTION("Malvar")
{
convertTo(I_RGBA_16U, I_RGBA_8U);
double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
std::cout << "16-bit - GBRG - Malvar - PSNR: " << PSNR << " min required: " << min_PSNR_Malvar << std::endl;
CHECK(PSNR >= min_PSNR_Malvar);
}
}
}
SECTION("GRBG")
{
const std::string filename =
if (readBinaryFile(filename, buffer)) {
col2im(buffer, I_Bayer_16U);
SECTION("Bilinear")
{
convertTo(I_RGBA_16U, I_RGBA_8U);
double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
std::cout << "16-bit - GRBG - Bilinear - PSNR: " << PSNR << " min required: " << min_PSNR_bilinear << std::endl;
CHECK(PSNR >= min_PSNR_bilinear);
}
SECTION("Malvar")
{
convertTo(I_RGBA_16U, I_RGBA_8U);
double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
std::cout << "16-bit - GRBG - Malvar - PSNR: " << PSNR << " min required: " << min_PSNR_Malvar << std::endl;
CHECK(PSNR >= min_PSNR_Malvar);
}
}
}
SECTION("RGGB")
{
const std::string filename =
if (readBinaryFile(filename, buffer)) {
col2im(buffer, I_Bayer_16U);
SECTION("Bilinear")
{
convertTo(I_RGBA_16U, I_RGBA_8U);
double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
std::cout << "16-bit - RGGB - Bilinear - PSNR: " << PSNR << " min required: " << min_PSNR_bilinear << std::endl;
CHECK(PSNR >= min_PSNR_bilinear);
}
SECTION("Malvar")
{
convertTo(I_RGBA_16U, I_RGBA_8U);
double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
std::cout << "16-bit - RGGB - Malvar - PSNR: " << PSNR << " min required: " << min_PSNR_Malvar << std::endl;
CHECK(PSNR >= min_PSNR_Malvar);
}
}
}
}
SECTION("8-bit")
{
std::vector<uint8_t> buffer(height * width);
SECTION("BGGR")
{
const std::string filename =
if (readBinaryFile(filename, buffer)) {
col2im(buffer, I_Bayer_8U);
SECTION("Bilinear")
{
double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
std::cout << "8-bit - BGGR - Bilinear - PSNR: " << PSNR <<" min required: " << min_PSNR_bilinear << std::endl;
CHECK(PSNR >= min_PSNR_bilinear);
}
SECTION("Malvar")
{
double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
std::cout << "8-bit - BGGR - Malvar - PSNR: " << PSNR << " min required: " << min_PSNR_Malvar << std::endl;
CHECK(PSNR >= min_PSNR_Malvar);
}
}
}
SECTION("GBRG")
{
const std::string filename =
if (readBinaryFile(filename, buffer)) {
col2im(buffer, I_Bayer_8U);
SECTION("Bilinear")
{
double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
std::cout << "8-bit - GBRG - Bilinear - PSNR: " << PSNR << " min required: " << min_PSNR_bilinear << std::endl;
CHECK(PSNR >= min_PSNR_bilinear);
}
SECTION("Malvar")
{
double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
std::cout << "8-bit - GBRG - Malvar - PSNR: " << PSNR << " min required: " << min_PSNR_Malvar << std::endl;
CHECK(PSNR >= min_PSNR_Malvar);
}
}
}
SECTION("GRBG")
{
const std::string filename =
if (readBinaryFile(filename, buffer)) {
col2im(buffer, I_Bayer_8U);
SECTION("Bilinear")
{
double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
std::cout << "8-bit - GRBG - Bilinear - PSNR: " << PSNR << " min required: " << min_PSNR_bilinear << std::endl;
CHECK(PSNR >= min_PSNR_bilinear);
}
SECTION("Malvar")
{
double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
std::cout << "8-bit - GRBG - Malvar - PSNR: " << PSNR << " min required: " << min_PSNR_Malvar << std::endl;
CHECK(PSNR >= min_PSNR_Malvar);
}
}
}
SECTION("RGGB")
{
const std::string filename =
if (readBinaryFile(filename, buffer)) {
col2im(buffer, I_Bayer_8U);
SECTION("Bilinear")
{
double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
std::cout << "8-bit - RGGB - Bilinear - PSNR: " << PSNR << " min required: " << min_PSNR_bilinear << std::endl;
CHECK(PSNR >= min_PSNR_bilinear);
}
SECTION("Malvar")
{
double PSNR = computePSNR(I_RGBA_8U, I_RGBA_8U_ref);
std::cout << "8-bit - RGGB - Malvar - PSNR: " << PSNR << " min required: " << min_PSNR_Malvar << std::endl;
CHECK(PSNR >= min_PSNR_Malvar);
}
}
}
}
}
#endif
template<typename Type>
bool test_hsv(const std::vector<Type> &hue, const std::vector<Type> &saturation,
const std::vector<Type> &value, const std::vector< std::vector<unsigned char> > &rgb_truth,
const std::vector< std::vector<double> > &hsv_truth, size_t step, size_t size, double max_range)
{
for (size_t i = 0; i < size; ++i) {
if (((hue[i]*max_range) != static_cast<Type>(hsv_truth[i][0])) ||
((saturation[i]*max_range) != static_cast<Type>(hsv_truth[i][1])) ||
((value[i]*max_range) != static_cast<Type>(hsv_truth[i][2]))) {
if (step == 3) {
std::cout << "Error in rgb to hsv conversion for rgb (";
}
else {
std::cout << "Error in rgba to hsv conversion for rgba (";
}
std::cout << static_cast<int>(rgb_truth[i][0]) << ","
<< static_cast<int>(rgb_truth[i][1]) << ","
<< static_cast<int>(rgb_truth[i][2]) << "): Expected hsv value: ("
<< static_cast<int>(hsv_truth[i][0]) << ","
<< static_cast<int>(hsv_truth[i][1]) << ","
<< static_cast<int>(hsv_truth[i][2]) << ") converted value: ("
<< static_cast<int>(hue[i]) << ","
<< static_cast<int>(saturation[i]) << ","
<< static_cast<int>(value[i]) << ")" << std::endl;
return false;
}
}
return true;
}
bool test_rgb(const std::vector<unsigned char> &rgb, const std::vector< std::vector<unsigned char> > rgb_truth,
const std::vector< std::vector<double> > &hsv_truth, size_t step, size_t size, double epsilon = 0.)
{
if (epsilon > 0.) {
for (size_t i = 0; i < size; ++i) {
std::cout << "Error in hsv to rgb conversion for hsv ("
<< static_cast<int>(hsv_truth[i][0]) << ","
<< static_cast<int>(hsv_truth[i][1]) << ","
<< static_cast<int>(hsv_truth[i][2]) << "): Expected rgb value: ("
<< static_cast<int>(rgb_truth[i][0]) << ","
<< static_cast<int>(rgb_truth[i][1]) << ","
<< static_cast<int>(rgb_truth[i][2]) << ") converted value: ("
<< static_cast<int>(rgb[i*step]) << ","
<< static_cast<int>(rgb[(i*step)+1]) << ","
<< static_cast<int>(rgb[(i*step)+2]) << ") epsilon: " << epsilon << std::endl;
return false;
}
}
}
else {
for (size_t i = 0; i < size; ++i) {
if ((rgb[i*step] != rgb_truth[i][0]) || (rgb[i*step+1] != rgb_truth[i][1]) || (rgb[i*step+2] != rgb_truth[i][2])) {
std::cout << "Error in hsv to rgb conversion for hsv ("
<< static_cast<int>(hsv_truth[i][0]) << ","
<< static_cast<int>(hsv_truth[i][1]) << ","
<< static_cast<int>(hsv_truth[i][2]) << "): Expected rgb value: ("
<< static_cast<int>(rgb_truth[i][0]) << ","
<< static_cast<int>(rgb_truth[i][1]) << ","
<< static_cast<int>(rgb_truth[i][2]) << ") converted value: ("
<< static_cast<int>(rgb[i*step]) << ","
<< static_cast<int>(rgb[(i*step)+1]) << ","
<< static_cast<int>(rgb[(i*step)+2]) << ")" << std::endl;
return false;
}
}
}
return true;
}
TEST_CASE("RGB to HSV conversion", "[image_conversion]")
{
std::vector< std::vector<unsigned char> > rgb_truth;
rgb_truth.push_back({ 0, 0, 0 });
rgb_truth.push_back({ 255, 255, 255 });
rgb_truth.push_back({ 255, 0, 0 });
rgb_truth.push_back({ 0, 255, 0 });
rgb_truth.push_back({ 0, 0, 255 });
rgb_truth.push_back({ 255, 255, 0 });
rgb_truth.push_back({ 0, 255, 255 });
rgb_truth.push_back({ 255, 0, 255 });
rgb_truth.push_back({ 128, 128, 128 });
rgb_truth.push_back({ 128, 128, 0 });
rgb_truth.push_back({ 128, 0, 0 });
rgb_truth.push_back({ 0, 128, 0 });
rgb_truth.push_back({ 0, 128, 128 });
rgb_truth.push_back({ 0, 0, 128 });
rgb_truth.push_back({ 128, 0, 128 });
double h_max;
bool h_full;
for (size_t test = 0; test < 2; ++test) {
if (test == 0) {
h_max = 255;
h_full = true;
}
else {
h_max = 180;
h_full = false;
}
std::vector< std::vector<double> > hsv_truth;
hsv_truth.push_back({ 0, 0, 0 });
hsv_truth.push_back({ 0, 0, 255 });
hsv_truth.push_back({ 0, 255, 255 });
hsv_truth.push_back({ h_max * 120 / 360, 255, 255 });
hsv_truth.push_back({ h_max * 240 / 360, 255, 255 });
hsv_truth.push_back({ h_max * 60 / 360, 255, 255 });
hsv_truth.push_back({ h_max * 180 / 360, 255, 255 });
hsv_truth.push_back({ h_max * 300 / 360, 255, 255 });
hsv_truth.push_back({ 0, 0, 128 });
hsv_truth.push_back({ h_max * 60 / 360, 255, 128 });
hsv_truth.push_back({ 0, 255, 128 });
hsv_truth.push_back({ h_max * 120 / 360, 255, 128 });
hsv_truth.push_back({ h_max * 180 / 360, 255, 128 });
hsv_truth.push_back({ h_max * 240 / 360, 255, 128 });
hsv_truth.push_back({ h_max * 300 / 360, 255, 128 });
size_t size = rgb_truth.size();
std::vector<unsigned char> rgb_truth_continuous;
for (size_t i = 0; i < size; ++i) {
for (size_t j = 0; j < rgb_truth[i].size(); ++j) {
rgb_truth_continuous.push_back(rgb_truth[i][j]);
}
}
std::vector<unsigned char> rgba_truth_continuous;
for (size_t i = 0; i < size; ++i) {
for (size_t j = 0; j < rgb_truth[i].size(); ++j) {
rgba_truth_continuous.push_back(rgb_truth[i][j]);
}
}
SECTION("RGB -> HSV (unsigned char) -> RGB")
{
std::vector<unsigned char> hue(size);
std::vector<unsigned char> saturation(size);
std::vector<unsigned char> value(size);
std::cout << "Test rgb -> hsv (unsigned char) conversion with h full scale: " << (h_full ? "yes" : "no") << std::endl;
reinterpret_cast<unsigned char *>(&hue.front()),
reinterpret_cast<unsigned char *>(&saturation.front()),
reinterpret_cast<unsigned char *>(&value.front()), static_cast<unsigned int>(size), h_full);
CHECK(test_hsv(hue, saturation, value, rgb_truth, hsv_truth, 3, size, 1.));
std::cout << "Test hsv (unsigned char) -> rgb conversion with h full scale: " << (h_full ? "yes" : "no") << std::endl;
std::vector< unsigned char> rgb_continuous(rgb_truth_continuous.size() * 3);
vpImageConvert::HSVToRGB(&hue.front(), &saturation.front(), &value.front(), &rgb_continuous.front(),
static_cast<unsigned int>(size), h_full);
CHECK(test_rgb(rgb_continuous, rgb_truth, hsv_truth, 3, size, 5.));
}
SECTION("RGBa -> HSV (unsigned char) -> RGBa")
{
std::vector<unsigned char> hue(size);
std::vector<unsigned char> saturation(size);
std::vector<unsigned char> value(size);
std::cout << "Test rgba -> hsv (unsigned char) conversion with h full scale: " << (h_full ? "yes" : "no") << std::endl;
reinterpret_cast<unsigned char *>(&hue.front()),
reinterpret_cast<unsigned char *>(&saturation.front()),
reinterpret_cast<unsigned char *>(&value.front()), static_cast<unsigned int>(size), h_full);
CHECK(test_hsv(hue, saturation, value, rgb_truth, hsv_truth, 4, size, 1.));
std::cout << "Test hsv (unsigned char) -> rgba conversion with h full scale: " << (h_full ? "yes" : "no") << std::endl;
std::vector< unsigned char> rgba_continuous(rgb_truth_continuous.size() * 4);
vpImageConvert::HSVToRGBa(&hue.front(), &saturation.front(), &value.front(), &rgba_continuous.front(),
static_cast<unsigned int>(size), h_full);
CHECK(test_rgb(rgba_continuous, rgb_truth, hsv_truth, 4, size, 5.));
}
if (h_full) {
SECTION("RGB -> HSV (double) -> RGB")
{
std::vector<double> hue(size);
std::vector<double> saturation(size);
std::vector<double> value(size);
std::cout << "Test rgb -> hsv (double) conversion" << std::endl;
reinterpret_cast<double *>(&hue.front()),
reinterpret_cast<double *>(&saturation.front()),
reinterpret_cast<double *>(&value.front()), static_cast<unsigned int>(size));
CHECK(test_hsv(hue, saturation, value, rgb_truth, hsv_truth, 3, size, 255.));
std::cout << "Test hsv (double) -> rgb conversion" << std::endl;
std::vector< unsigned char> rgb_continuous(rgb_truth_continuous.size());
vpImageConvert::HSVToRGB(&hue.front(), &saturation.front(), &value.front(), &rgb_continuous.front(),
static_cast<unsigned int>(size));
CHECK(test_rgb(rgb_continuous, rgb_truth, hsv_truth, 3, size));
}
}
if (h_full) {
SECTION("RGBa -> HSV (double) -> RGBa")
{
std::vector<double> hue(size);
std::vector<double> saturation(size);
std::vector<double> value(size);
std::cout << "Test rgba -> hsv (double) conversion" << std::endl;
reinterpret_cast<double *>(&hue.front()),
reinterpret_cast<double *>(&saturation.front()),
reinterpret_cast<double *>(&value.front()), static_cast<unsigned int>(size));
CHECK(test_hsv(hue, saturation, value, rgb_truth, hsv_truth, 4, size, 255.));
std::cout << "Test hsv (double) -> rgba conversion" << std::endl;
std::vector< unsigned char> rgba_continuous(rgb_truth_continuous.size()*4);
vpImageConvert::HSVToRGBa(&hue.front(), &saturation.front(), &value.front(), &rgba_continuous.front(),
static_cast<unsigned int>(size));
CHECK(test_rgb(rgba_continuous, rgb_truth, hsv_truth, 4, size));
}
}
}
}
int main(int argc, char *argv[])
{
Catch::Session session;
session.applyCommandLine(argc, argv);
int numFailed = session.run();
std::cout << (numFailed ? "Test failed" : "Test succeed") << std::endl;
return numFailed;
}
#else
int main() { return EXIT_SUCCESS; }
#endif
Implementation of column vector and the associated operations.
static void HSVToRGBa(const double *hue, const double *saturation, const double *value, unsigned char *rgba, unsigned int size)
static void demosaicBGGRToRGBaBilinear(const uint8_t *bggr, uint8_t *rgba, unsigned int width, unsigned int height, unsigned int nThreads=0)
static void demosaicGRBGToRGBaBilinear(const uint8_t *grbg, uint8_t *rgba, unsigned int width, unsigned int height, unsigned int nThreads=0)
static void RGBToHSV(const unsigned char *rgb, double *hue, double *saturation, double *value, unsigned int size)
static void demosaicGRBGToRGBaMalvar(const uint8_t *grbg, uint8_t *rgba, unsigned int width, unsigned int height, unsigned int nThreads=0)
static void demosaicGBRGToRGBaMalvar(const uint8_t *gbrg, uint8_t *rgba, unsigned int width, unsigned int height, unsigned int nThreads=0)
static void merge(const vpImage< unsigned char > *R, const vpImage< unsigned char > *G, const vpImage< unsigned char > *B, const vpImage< unsigned char > *a, vpImage< vpRGBa > &RGBa)
static void demosaicBGGRToRGBaMalvar(const uint8_t *bggr, uint8_t *rgba, unsigned int width, unsigned int height, unsigned int nThreads=0)
static void demosaicGBRGToRGBaBilinear(const uint8_t *gbrg, uint8_t *rgba, unsigned int width, unsigned int height, unsigned int nThreads=0)
static void split(const vpImage< vpRGBa > &src, vpImage< unsigned char > *pR, vpImage< unsigned char > *pG, vpImage< unsigned char > *pB, vpImage< unsigned char > *pa=nullptr)
static void RGBaToHSV(const unsigned char *rgba, double *hue, double *saturation, double *value, unsigned int size)
static void demosaicRGGBToRGBaMalvar(const uint8_t *rggb, uint8_t *rgba, unsigned int width, unsigned int height, unsigned int nThreads=0)
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
static void RGBToGrey(unsigned char *rgb, unsigned char *grey, unsigned int width, unsigned int height, bool flip=false)
static void RGBToRGBa(unsigned char *rgb, unsigned char *rgba, unsigned int size)
static void BGRaToGrey(unsigned char *bgra, unsigned char *grey, unsigned int width, unsigned int height, bool flip=false, unsigned int nThreads=0)
static void BGRToGrey(unsigned char *bgr, unsigned char *grey, unsigned int width, unsigned int height, bool flip=false, unsigned int nThreads=0)
static void demosaicRGGBToRGBaBilinear(const uint8_t *rggb, uint8_t *rgba, unsigned int width, unsigned int height, unsigned int nThreads=0)
static void BGRaToRGBa(unsigned char *bgra, unsigned char *rgba, unsigned int width, unsigned int height, bool flip=false)
static void RGBaToRGB(unsigned char *rgba, unsigned char *rgb, unsigned int size)
static void HSVToRGB(const double *hue, const double *saturation, const double *value, unsigned char *rgb, unsigned int size)
static void read(vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
unsigned int getWidth() const
unsigned int getSize() const
Type * bitmap
points toward the bitmap
unsigned int getHeight() const
static double sqr(double x)
static bool equal(double x, double y, double threshold=0.001)
VISP_EXPORT uint16_t swap16bits(uint16_t val)