42#include <visp3/core/vpRGBa.h>
43#include <visp3/core/vpHSV.h>
44#include <visp3/core/vpImage.h>
45#include <visp3/core/vpImageFilter.h>
49#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
52#ifdef ENABLE_VISP_NAMESPACE
56#ifndef DOXYGEN_SHOULD_SKIP_THIS
59 const unsigned int nbRows = I.getRows(), nbCols = I.getCols();
60 for (
unsigned int r = 1;
r < nbRows - 1; ++
r) {
61 for (
unsigned int c = 1; c < nbCols - 1; ++c) {
62 for (
unsigned int i = 0;
i <= 2; ++
i) {
63 for (
unsigned int j = 0;
j <= 2; ++
j) {
64 GIy[
r][c] += filter[
i][
j] * I[
r-1 +
i][c-1 +
j];
73 const unsigned int nbRows = I.getRows(), nbCols = I.getCols();
74 GIx.
resize(nbRows, nbCols, 0.);
75 GIy.
resize(nbRows, nbCols, 0.);
76 gradientFilter(I, filterX, GIx);
77 gradientFilter(I, filterY, GIy);
80static bool checkBooleanMask(
const vpImage<bool> *p_mask,
const unsigned int &r,
const unsigned int &c)
82 bool computeVal =
true;
83 if (p_mask !=
nullptr) {
84 computeVal = (*p_mask)[
r][c];
89template <
typename ArithmeticType,
typename FilterType,
bool useFullScale>
92 const unsigned int nbRows = I.getRows(), nbCols = I.getCols();
93 GIx.
resize(nbRows, nbCols, 0.);
94 std::vector<FilterType> filter(3);
99 filter = { 1., 2., 1. };
104 filter = { 3., 10., 3. };
112 for (
unsigned char i = 0;
i < 3; ++
i) {
113 filter[
i] = filter[
i] / scale;
116 auto checkBooleanPatch = [](
const vpImage<bool> *p_mask,
const unsigned int &
r,
const unsigned int &c,
const unsigned int &
h,
const unsigned int &
w)
121 bool hasToCompute = (*p_mask)[
r][c];
124 hasToCompute |= (*p_mask)[
r][c + 1];
126 hasToCompute |= (*p_mask)[
r + 1][c + 1];
131 hasToCompute |= (*p_mask)[
r + 1][c];
135 hasToCompute |= (*p_mask)[
r - 1][c];
137 hasToCompute |= (*p_mask)[
r - 1][c + 1];
143 const unsigned int rStop = nbRows - 1, cStop = nbCols - 1;
147 for (
unsigned int r = 1;
r < rStop; ++
r) {
149 if (checkBooleanPatch(p_mask, r, 0, nbRows, nbCols)) {
150 IabsDiff[
r][0] = I[
r][1].V - I[
r][0].V;
154 for (
unsigned int c = 1; c < cStop; ++c) {
155 if (checkBooleanPatch(p_mask, r, c, nbRows, nbCols)) {
157 IabsDiff[
r][c] = I[
r][c + 1].V - I[
r][c].V;
162 for (
unsigned int r = 1;
r < rStop; ++
r) {
163 for (
unsigned int c = 1; c < cStop; ++c) {
164 if (checkBooleanMask(p_mask, r, c)) {
166 for (
int dr = -1; dr <= 1; ++dr) {
167 GIx[
r][c] += filter[dr + 1] * (IabsDiff[
r + dr][c - 1] + IabsDiff[
r + dr][c]);
174template <
typename ArithmeticType,
typename FilterType,
bool useFullScale>
177 const unsigned int nbRows = I.getRows(), nbCols = I.getCols();
178 std::vector<FilterType> filter(3);
182 filter = { 1., 2., 1. };
186 filter = { 3., 10., 3. };
192 for (
unsigned char i = 0;
i < 3; ++
i) {
193 filter[
i] = filter[
i] / scale;
196 const unsigned int rStop = nbRows - 1, cStop = nbCols - 1;
199 auto checkBooleanPatch = [](
const vpImage<bool> *p_mask,
const unsigned int &
r,
const unsigned int &c,
const unsigned int &
h,
const unsigned int &
w)
205 bool hasToCompute = (*p_mask)[
r][c];
207 hasToCompute |= (*p_mask)[
r][c + 1];
209 hasToCompute |= (*p_mask)[
r + 1][c + 1];
214 hasToCompute |= (*p_mask)[
r + 1][c];
218 hasToCompute |= (*p_mask)[
r][c - 1];
220 hasToCompute |= (*p_mask)[
r + 1][c - 1];
227 for (
unsigned int c = 0; c < nbCols; ++c) {
228 if (checkBooleanPatch(p_mask, 0, c, nbRows, nbCols)) {
229 IabsDiff[0][c] = I[1][c].V - I[0][c].V;
234 for (
unsigned int r = 1;
r < rStop; ++
r) {
235 for (
unsigned int c = 0; c < nbCols; ++c) {
237 if (checkBooleanPatch(p_mask, r, c, nbRows, nbCols)) {
238 IabsDiff[
r][c] = I[
r + 1][c].V - I[
r][c].V;
244 for (
unsigned int r = 1;
r < rStop; ++
r) {
245 for (
unsigned int c = 1; c < cStop; ++c) {
246 if (checkBooleanMask(p_mask, r, c)) {
248 for (
int dc = -1; dc <= 1; ++dc) {
249 GIy[
r][c] += filter[dc + 1] * (IabsDiff[
r - 1][c + dc] + IabsDiff[
r][c + dc]);
256template <
typename ArithmeticType,
bool useFullScale>
259 const unsigned int nbRows = I.getRows(), nbCols = I.getCols();
260 GIx.
resize(nbRows, nbCols, 0.);
261 GIy.
resize(nbRows, nbCols, 0.);
262 gradientFilterX(I, GIx, p_mask, type);
263 gradientFilterY(I, GIy, p_mask, type);
269 bool isSuccess =
true;
272 vpHSVTests::vpInputDataset dataset;
273 bool useSobel =
false;
275 filterX[0][0] = -1.; filterX[0][1] = 0.; filterX[0][2] = 1.;
276 filterX[1][0] = (useSobel ? -2. : -1.); filterX[1][1] = 0.; filterX[1][2] = (useSobel ? 2. : 1.);
277 filterX[2][0] = -1.; filterX[2][1] = 0.; filterX[2][2] = 1.;
280 filterY[0][0] = -1.; filterY[0][1] = (useSobel ? -2. : -1.); filterY[0][2] = -1.;
281 filterY[1][0] = 0.; filterY[1][1] = 0.; filterY[1][2] = 0.;
282 filterY[2][0] = 1.; filterY[2][1] = (useSobel ? 2. : 1.); filterY[2][2] = 1.;
287 std::vector<vpImageFilter::vpCannyFilteringAndGradientType> types = {
292 std::vector<int> nbThreads = { 1, 2 };
295 for (
unsigned int i = 0;
i < 2; ++
i) {
297 p_mask = &dataset.m_Imask;
299 for (
auto type: types) {
300 for (
auto nbThread: nbThreads) {
301 for (
auto input: dataset.m_hsvUCtrue) {
303 gradientFilter(input.second.m_I, GIx_ref, GIy_ref, p_mask, type);
304 bool isSuccessGIx = vpHSVTests::areAlmostEqual(GIx,
"GIx", GIx_ref,
"GIx_ref");
305 bool isSuccessGIy = vpHSVTests::areAlmostEqual(GIy,
"GIy", GIy_ref,
"GIy_ref");
306 isSuccess = isSuccess && isSuccessGIx && isSuccessGIy;
313 if (!(isSuccessGIx && isSuccessGIy)) {
315 std::cout <<
"nbThread: " << nbThread << std::endl;
316 std::cout <<
"mask ? : " << (p_mask ? std::string(
"true") : std::string(
"false")) << std::endl;
317 vpHSVTests::print(input.second.m_I, input.first);
318 vpHSVTests::print(GIx,
"GIx");
319 vpHSVTests::print(GIy,
"GIy");
320 vpHSVTests::print(GIx_ref,
"GIx_ref");
321 vpHSVTests::print(GIy_ref,
"GIy_ref");
325 for (
auto input: dataset.m_hsvUCfalse) {
327 gradientFilter(input.second.m_I, GIx_ref, GIy_ref, p_mask, type);
328 bool isSuccessGIx = vpHSVTests::areAlmostEqual(GIx,
"GIx", GIx_ref,
"GIx_ref");
329 bool isSuccessGIy = vpHSVTests::areAlmostEqual(GIy,
"GIy", GIy_ref,
"GIy_ref");
330 isSuccess = isSuccess && isSuccessGIx && isSuccessGIy;
337 if (!(isSuccessGIx && isSuccessGIy)) {
339 std::cout <<
"nbThread: " << nbThread << std::endl;
340 std::cout <<
"mask ? : " << (p_mask ? std::string(
"true") : std::string(
"false")) << std::endl;
341 vpHSVTests::print(input.second.m_I, input.first);
342 vpHSVTests::print(GIx,
"GIx");
343 vpHSVTests::print(GIy,
"GIy");
344 vpHSVTests::print(GIx_ref,
"GIx_ref");
345 vpHSVTests::print(GIy_ref,
"GIy_ref");
349 for (
auto input: dataset.m_hsvDouble) {
351 gradientFilter(input.second.m_I, GIx_ref, GIy_ref, p_mask, type);
352 bool isSuccessGIx = vpHSVTests::areAlmostEqual(GIx,
"GIx", GIx_ref,
"GIx_ref");
353 bool isSuccessGIy = vpHSVTests::areAlmostEqual(GIy,
"GIy", GIy_ref,
"GIy_ref");
354 isSuccess = isSuccess && isSuccessGIx && isSuccessGIy;
361 if (!(isSuccessGIx && isSuccessGIy)) {
363 std::cout <<
"nbThread: " << nbThread << std::endl;
364 std::cout <<
"mask ? : " << (p_mask ? std::string(
"true") : std::string(
"false")) << std::endl;
365 vpHSVTests::print(input.second.m_I, input.first);
366 vpHSVTests::print(GIx,
"GIx");
367 vpHSVTests::print(GIy,
"GIy");
368 vpHSVTests::print(GIx_ref,
"GIx_ref");
369 vpHSVTests::print(GIy_ref,
"GIy_ref");
377 std::cout <<
"All tests were successful !" << std::endl;
380 std::cerr <<
"ERROR: Something went wrong !" << std::endl;
387 std::cout <<
"vpHSV class is not available, please use CXX 11 standard" << std::endl;
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