#include <iostream>
#include <limits>
#include <visp3/core/vpRGBa.h>
#include <visp3/core/vpHSV.h>
#include <visp3/core/vpImage.h>
#include <visp3/core/vpImageFilter.h>
#include "hsvUtils.h"
#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
#include <type_traits>
#ifdef ENABLE_VISP_NAMESPACE
#endif
#ifndef DOXYGEN_SHOULD_SKIP_THIS
{
const unsigned int nbRows = I.getRows(), nbCols = I.getCols();
for (unsigned int r = 1; r < nbRows - 1; ++r) {
for (unsigned int c = 1; c < nbCols - 1; ++c) {
for (unsigned int i = 0; i <= 2; ++i) {
for (unsigned int j = 0; j <= 2; ++j) {
GIy[r][c] += filter[i][j] * I[r-1 + i][c-1 + j];
}
}
}
}
}
{
const unsigned int nbRows = I.getRows(), nbCols = I.getCols();
GIx.
resize(nbRows, nbCols, 0.);
GIy.
resize(nbRows, nbCols, 0.);
gradientFilter(I, filterX, GIx);
gradientFilter(I, filterY, GIy);
}
static bool checkBooleanMask(
const vpImage<bool> *p_mask,
const unsigned int &r,
const unsigned int &c)
{
bool computeVal = true;
if (p_mask != nullptr) {
computeVal = (*p_mask)[
r][c];
}
return computeVal;
}
template <typename ArithmeticType, typename FilterType, bool useFullScale>
{
const unsigned int nbRows = I.getRows(), nbCols = I.getCols();
GIx.
resize(nbRows, nbCols, 0.);
std::vector<FilterType> filter(3);
FilterType scale;
std::string name;
switch (type) {
filter = { 1., 2., 1. };
scale = 8.;
name = "Sobel";
break;
filter = { 3., 10., 3. };
scale = 32.;
name = "Scharr";
break;
default:
}
for (
unsigned char i = 0;
i < 3; ++
i) {
filter[
i] = filter[
i] / scale;
}
auto checkBooleanPatch = [](
const vpImage<bool> *p_mask,
const unsigned int &
r,
const unsigned int &c,
const unsigned int &
h,
const unsigned int &
w)
{
if (!p_mask) {
return true;
}
bool hasToCompute = (*p_mask)[
r][c];
if (c < w - 1) {
hasToCompute |= (*p_mask)[
r][c + 1];
if (r < h - 1) {
hasToCompute |= (*p_mask)[
r + 1][c + 1];
}
}
if (r < h - 1) {
hasToCompute |= (*p_mask)[
r + 1][c];
}
if (r > 1) {
hasToCompute |= (*p_mask)[
r - 1][c];
if (c < w - 1) {
hasToCompute |= (*p_mask)[
r - 1][c + 1];
}
}
return hasToCompute;
};
const unsigned int rStop = nbRows - 1, cStop = nbCols - 1;
for (
unsigned int r = 1;
r < rStop; ++
r) {
if (checkBooleanPatch(p_mask, r, 0, nbRows, nbCols)) {
IabsDiff[
r][0] = I[
r][1].V - I[
r][0].V;
}
for (unsigned int c = 1; c < cStop; ++c) {
if (checkBooleanPatch(p_mask, r, c, nbRows, nbCols)) {
IabsDiff[
r][c] = I[
r][c + 1].V - I[
r][c].V;
}
}
}
for (
unsigned int r = 1;
r < rStop; ++
r) {
for (unsigned int c = 1; c < cStop; ++c) {
if (checkBooleanMask(p_mask, r, c)) {
for (int dr = -1; dr <= 1; ++dr) {
GIx[
r][c] += filter[dr + 1] * (IabsDiff[
r + dr][c - 1] + IabsDiff[
r + dr][c]);
}
}
}
}
}
template <typename ArithmeticType, typename FilterType, bool useFullScale>
{
const unsigned int nbRows = I.getRows(), nbCols = I.getCols();
std::vector<FilterType> filter(3);
FilterType scale;
switch (type) {
filter = { 1., 2., 1. };
scale = 8.;
break;
filter = { 3., 10., 3. };
scale = 32.;
break;
default:
}
for (
unsigned char i = 0;
i < 3; ++
i) {
filter[
i] = filter[
i] / scale;
}
const unsigned int rStop = nbRows - 1, cStop = nbCols - 1;
auto checkBooleanPatch = [](
const vpImage<bool> *p_mask,
const unsigned int &
r,
const unsigned int &c,
const unsigned int &
h,
const unsigned int &
w)
{
if (!p_mask) {
return true;
}
bool hasToCompute = (*p_mask)[
r][c];
if (c < w - 1) {
hasToCompute |= (*p_mask)[
r][c + 1];
if (r < h - 1) {
hasToCompute |= (*p_mask)[
r + 1][c + 1];
}
}
if (r < h - 1) {
hasToCompute |= (*p_mask)[
r + 1][c];
}
if (c > 1) {
hasToCompute |= (*p_mask)[
r][c - 1];
if (r < h - 1) {
hasToCompute |= (*p_mask)[
r + 1][c - 1];
}
}
return hasToCompute;
};
for (unsigned int c = 0; c < nbCols; ++c) {
if (checkBooleanPatch(p_mask, 0, c, nbRows, nbCols)) {
IabsDiff[0][c] = I[1][c].V - I[0][c].V;
}
}
for (
unsigned int r = 1;
r < rStop; ++
r) {
for (unsigned int c = 0; c < nbCols; ++c) {
if (checkBooleanPatch(p_mask, r, c, nbRows, nbCols)) {
IabsDiff[
r][c] = I[
r + 1][c].V - I[
r][c].V;
}
}
}
for (
unsigned int r = 1;
r < rStop; ++
r) {
for (unsigned int c = 1; c < cStop; ++c) {
if (checkBooleanMask(p_mask, r, c)) {
for (int dc = -1; dc <= 1; ++dc) {
GIy[
r][c] += filter[dc + 1] * (IabsDiff[
r - 1][c + dc] + IabsDiff[
r][c + dc]);
}
}
}
}
}
template <typename ArithmeticType, bool useFullScale>
{
const unsigned int nbRows = I.getRows(), nbCols = I.getCols();
GIx.
resize(nbRows, nbCols, 0.);
GIy.
resize(nbRows, nbCols, 0.);
gradientFilterX(I, GIx, p_mask, type);
gradientFilterY(I, GIy, p_mask, type);
}
#endif
int main()
{
bool isSuccess = true;
vpHSVTests::vpInputDataset dataset;
bool useSobel = false;
filterX[0][0] = -1.; filterX[0][1] = 0.; filterX[0][2] = 1.;
filterX[1][0] = (useSobel ? -2. : -1.); filterX[1][1] = 0.; filterX[1][2] = (useSobel ? 2. : 1.);
filterX[2][0] = -1.; filterX[2][1] = 0.; filterX[2][2] = 1.;
filterY[0][0] = -1.; filterY[0][1] = (useSobel ? -2. : -1.); filterY[0][2] = -1.;
filterY[1][0] = 0.; filterY[1][1] = 0.; filterY[1][2] = 0.;
filterY[2][0] = 1.; filterY[2][1] = (useSobel ? 2. : 1.); filterY[2][2] = 1.;
std::vector<vpImageFilter::vpCannyFilteringAndGradientType> types = {
};
std::vector<int> nbThreads = { 1, 2 };
for (
unsigned int i = 0;
i < 2; ++
i) {
if (i == 1) {
p_mask = &dataset.m_Imask;
}
for (auto type: types) {
for (auto nbThread: nbThreads) {
for (auto input: dataset.m_hsvUCtrue) {
gradientFilter(input.second.m_I, GIx_ref, GIy_ref, p_mask, type);
bool isSuccessGIx = vpHSVTests::areAlmostEqual(GIx, "GIx", GIx_ref, "GIx_ref");
bool isSuccessGIy = vpHSVTests::areAlmostEqual(GIy, "GIy", GIy_ref, "GIy_ref");
isSuccess = isSuccess && isSuccessGIx && isSuccessGIy;
if (!isSuccessGIx) {
}
if (!isSuccessGIy) {
}
if (!(isSuccessGIx && isSuccessGIy)) {
std::cout << "nbThread: " << nbThread << std::endl;
std::cout << "mask ? : " << (p_mask ? std::string("true") : std::string("false")) << std::endl;
vpHSVTests::print(input.second.m_I, input.first);
vpHSVTests::print(GIx, "GIx");
vpHSVTests::print(GIy, "GIy");
vpHSVTests::print(GIx_ref, "GIx_ref");
vpHSVTests::print(GIy_ref, "GIy_ref");
}
}
for (auto input: dataset.m_hsvUCfalse) {
gradientFilter(input.second.m_I, GIx_ref, GIy_ref, p_mask, type);
bool isSuccessGIx = vpHSVTests::areAlmostEqual(GIx, "GIx", GIx_ref, "GIx_ref");
bool isSuccessGIy = vpHSVTests::areAlmostEqual(GIy, "GIy", GIy_ref, "GIy_ref");
isSuccess = isSuccess && isSuccessGIx && isSuccessGIy;
if (!isSuccessGIx) {
}
if (!isSuccessGIy) {
}
if (!(isSuccessGIx && isSuccessGIy)) {
std::cout << "nbThread: " << nbThread << std::endl;
std::cout << "mask ? : " << (p_mask ? std::string("true") : std::string("false")) << std::endl;
vpHSVTests::print(input.second.m_I, input.first);
vpHSVTests::print(GIx, "GIx");
vpHSVTests::print(GIy, "GIy");
vpHSVTests::print(GIx_ref, "GIx_ref");
vpHSVTests::print(GIy_ref, "GIy_ref");
}
}
for (auto input: dataset.m_hsvDouble) {
gradientFilter(input.second.m_I, GIx_ref, GIy_ref, p_mask, type);
bool isSuccessGIx = vpHSVTests::areAlmostEqual(GIx, "GIx", GIx_ref, "GIx_ref");
bool isSuccessGIy = vpHSVTests::areAlmostEqual(GIy, "GIy", GIy_ref, "GIy_ref");
isSuccess = isSuccess && isSuccessGIx && isSuccessGIy;
if (!isSuccessGIx) {
}
if (!isSuccessGIy) {
}
if (!(isSuccessGIx && isSuccessGIy)) {
std::cout << "nbThread: " << nbThread << std::endl;
std::cout << "mask ? : " << (p_mask ? std::string("true") : std::string("false")) << std::endl;
vpHSVTests::print(input.second.m_I, input.first);
vpHSVTests::print(GIx, "GIx");
vpHSVTests::print(GIy, "GIy");
vpHSVTests::print(GIx_ref, "GIx_ref");
vpHSVTests::print(GIy_ref, "GIy_ref");
}
}
}
}
}
if (isSuccess) {
std::cout << "All tests were successful !" << std::endl;
return EXIT_SUCCESS;
}
std::cerr << "ERROR: Something went wrong !" << std::endl;
return EXIT_FAILURE;
}
#else
int main()
{
std::cout << "vpHSV class is not available, please use CXX 11 standard" << std::endl;
return EXIT_SUCCESS;
}
#endif
error that can be emitted by ViSP classes.
@ badValue
Used to indicate that a value is not in the allowed range.
Class implementing the HSV pixel format.
static std::string vpCannyFiltAndGradTypeToStr(const vpCannyFilteringAndGradientType &type)
Cast a vpImageFilter::vpCannyFilteringAndGradientType into a string, to know its name.
static void gradientFilter(const vpImage< vpHSV< ArithmeticType, useFullScale > > &I, vpImage< FilterType > &GIx, vpImage< FilterType > &GIy, const int &nbThread=-1, const vpImage< bool > *p_mask=nullptr, const vpImageFilter::vpCannyFilteringAndGradientType &type=CANNY_GBLUR_SCHARR_FILTERING)
Compute the horizontal and vertical gradients for HSV images.
vpCannyFilteringAndGradientType
Canny filter and gradient operators to apply on the image before the edge detection stage.
@ CANNY_GBLUR_SOBEL_FILTERING
Apply Gaussian blur + Sobel operator on the input image.
@ CANNY_GBLUR_SCHARR_FILTERING
Apply Gaussian blur + Scharr operator on the input image.
Definition of the vpImage class member functions.
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization