Skip to content

Commit

Permalink
[CORPS] Reordered the medians to keep R, G, B ordering and added tests
Browse files Browse the repository at this point in the history
  • Loading branch information
rlagneau authored and fspindle committed Aug 30, 2023
1 parent 2e9e2db commit 7e495db
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 32 deletions.
20 changes: 12 additions & 8 deletions modules/core/src/image/vpImageFilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,20 +184,24 @@ double vpImageFilter::median(const vpImage<unsigned char> &Isrc)
}

/**
* \brief Calculates the median value of a single channel
* The algorithm is based on based on https://github.com/arnaudgelas/OpenCVExamples/blob/master/cvMat/Statistics/Median/Median.cpp
* \brief Calculates the median value of a vpRGBa image.
* The result is ordered in RGB format.
* \param[in] Isrc RGB image in ViSP format. Alpha channel is ignored.
* \return std::vector<double> meds such as meds[0] = red-channel-median meds[1] = green-channel-median
* and meds[2] = blue-channel-median.
* \sa \ref vpImageFilter::median() "vpImageFilter::median(const cv::Mat)"
*/
std::vector<double> vpImageFilter::median(const vpImage<vpRGBa> &Isrc)
{
cv::Mat cv_I;
vpImageConvert::convert(Isrc, cv_I);
cv::Mat cv_I_bgr;
vpImageConvert::convert(Isrc, cv_I_bgr);
std::vector<cv::Mat> channels;
cv::split(cv_I, channels);
std::vector<double> meds;
for (unsigned char i = 0; i < 3; i++) {
meds.push_back(median(channels[i]));
cv::split(cv_I_bgr, channels);
std::vector<double> meds(3);
const int orderMeds[] = { 2, 1, 0 }; // To keep the order R, G, B
const int orderCvChannels[] = { 0, 1, 2 }; // Because the order of the cv::Mat is B, G, R
for (unsigned int i = 0; i < 3; i++) {
meds[orderMeds[i]] = median(channels[orderCvChannels[i]]);
}
return meds;
}
Expand Down
91 changes: 67 additions & 24 deletions modules/core/test/image-with-dataset/testImageFilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,8 @@ int main(int argc, const char *argv[])
if (ipath != env_ipath) {
std::cout << std::endl << "WARNING: " << std::endl;
std::cout << " Since -i <visp image path=" << ipath << "> "
<< " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
<< " we skip the environment variable." << std::endl;
<< " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
<< " we skip the environment variable." << std::endl;
}
}

Expand Down Expand Up @@ -306,14 +306,14 @@ int main(int argc, const char *argv[])

std::cout << "\nTest correlation on small image:" << std::endl;
std::cout << "(I_correlation_1 == matImg_correlation_1)? "
<< check_results(matImg_correlation_1, I_correlation_1, kernel_1.getRows() / 2, kernel_1.getCols() / 2)
<< std::endl;
<< check_results(matImg_correlation_1, I_correlation_1, kernel_1.getRows() / 2, kernel_1.getCols() / 2)
<< std::endl;
std::cout << "(I_correlation_2 == matImg_correlation_2)? "
<< check_results(matImg_correlation_2, I_correlation_2, kernel_2.getRows() / 2, kernel_2.getCols() / 2)
<< std::endl;
<< check_results(matImg_correlation_2, I_correlation_2, kernel_2.getRows() / 2, kernel_2.getCols() / 2)
<< std::endl;
std::cout << "(I_correlation_3 == matImg_correlation_3)? "
<< check_results(matImg_correlation_3, I_correlation_3, kernel_3.getRows() / 2, kernel_3.getCols() / 2)
<< std::endl;
<< check_results(matImg_correlation_3, I_correlation_3, kernel_3.getRows() / 2, kernel_3.getCols() / 2)
<< std::endl;
#endif

// Test convolution
Expand Down Expand Up @@ -348,19 +348,20 @@ int main(int argc, const char *argv[])

std::cout << "\nTest convolution on small image:" << std::endl;
std::cout << "(I_convolution_1 == matImg_convolution_1)? "
<< check_results(matImg_convolution_1, I_convolution_1, kernel_1.getRows() / 2, kernel_1.getCols() / 2)
<< std::endl;
<< check_results(matImg_convolution_1, I_convolution_1, kernel_1.getRows() / 2, kernel_1.getCols() / 2)
<< std::endl;
std::cout << "(I_convolution_2 == matImg_convolution_2)? "
<< check_results(matImg_convolution_2, I_convolution_2, kernel_2.getRows() / 2, kernel_2.getCols() / 2)
<< std::endl;
<< check_results(matImg_convolution_2, I_convolution_2, kernel_2.getRows() / 2, kernel_2.getCols() / 2)
<< std::endl;
std::cout << "(I_convolution_3 == matImg_convolution_3)? "
<< check_results(matImg_convolution_3, I_convolution_3, kernel_3.getRows() / 2, kernel_3.getCols() / 2)
<< std::endl;
<< check_results(matImg_convolution_3, I_convolution_3, kernel_3.getRows() / 2, kernel_3.getCols() / 2)
<< std::endl;
#endif
if (opt_ppath.empty()) {
filename = vpIoTools::createFilePath(ipath, "Klimt/Klimt.pgm");
vpImageIo::read(I, filename);
} else {
}
else {
filename = opt_ppath;
vpImageIo::read(I, filename);
printf("Image \"%s\" read successfully\n", filename.c_str());
Expand Down Expand Up @@ -472,8 +473,8 @@ int main(int argc, const char *argv[])

std::cout << "\nTest Sobel on Klimt image:" << std::endl;
std::cout << "(I_sobel_x == matImg_sobel_x)? "
<< check_results(matImg_sobel_x, I_sobel_x, kernel_sobel_x.getRows() / 2, kernel_sobel_x.getCols() / 2)
<< std::endl;
<< check_results(matImg_sobel_x, I_sobel_x, kernel_sobel_x.getRows() / 2, kernel_sobel_x.getCols() / 2)
<< std::endl;
#endif

vpImage<double> I_double, Iu, Iv;
Expand All @@ -488,11 +489,11 @@ int main(int argc, const char *argv[])
cv::Sobel(matImg, matImg_sobel_y, CV_64F, 0, 1, 5);

std::cout << "(Iu == matImg_sobel_x)? "
<< check_results(matImg_sobel_x, Iu, kernel_sobel_x.getRows() / 2, kernel_sobel_x.getCols() / 2)
<< std::endl;
<< check_results(matImg_sobel_x, Iu, kernel_sobel_x.getRows() / 2, kernel_sobel_x.getCols() / 2)
<< std::endl;
std::cout << "(Iv == matImg_sobel_y)? "
<< check_results(matImg_sobel_y, Iv, kernel_sobel_x.getRows() / 2, kernel_sobel_x.getCols() / 2)
<< std::endl;
<< check_results(matImg_sobel_y, Iv, kernel_sobel_x.getRows() / 2, kernel_sobel_x.getCols() / 2)
<< std::endl;
#endif

// Test Sobel separable filters
Expand Down Expand Up @@ -523,6 +524,45 @@ int main(int argc, const char *argv[])
std::cerr << "Failed separable filter!" << std::endl;
return EXIT_FAILURE;
}

// Test median filter on gray-scale image
std::cout << "\nTest median on grayscale image:" << std::endl;
vpImage<unsigned char> I_median(3, 3);
for (unsigned int r = 0; r < 3; r++) {
for (unsigned int c = 0; c < 3; c++) {
I_median[r][c] = r * 3 + c;
}
}
double median = vpImageFilter::median(I_median);
double expectedMedian = 4.;
test = (median == expectedMedian);
std::cout << "(median (=" << median << ") == expectedMedian(" << expectedMedian << "))? " << test << std::endl;

if (!test) {
std::cerr << "Failed median filter on gray-scale image!" << std::endl;
return EXIT_FAILURE;
}

std::cout << "\nTest median on vpRGBa image:" << std::endl;
vpImage<vpRGBa> I_median_rgba(3, 3);
for (unsigned int r = 0; r < 3; r++) {
for (unsigned int c = 0; c < 3; c++) {
I_median_rgba[r][c].R = r * 3 + c;
I_median_rgba[r][c].G = 2 * (r * 3 + c);
I_median_rgba[r][c].B = 3 * (r * 3 + c);
}
}
std::vector<double> median_rgba = vpImageFilter::median(I_median_rgba);
std::vector<double> expected_median_rgba = { 4, 8, 12 };
for (unsigned int i = 0; i < 3; i++) {
bool test_local = (median_rgba[i] == expected_median_rgba[i]);
test &= test;
std::cout << "(median_rgba[" << i << "] (=" << median_rgba[i] << ") == expected_median_rgba[" << i << "] ( " << expected_median_rgba[i] << "))? " << test_local << std::endl;
}
if (!test) {
std::cerr << "Failed median filter on vpRGBa image!" << std::endl;
return EXIT_FAILURE;
}
#endif
}
{
Expand All @@ -536,7 +576,8 @@ int main(int argc, const char *argv[])
if (opt_ppath.empty()) {
filename = vpIoTools::createFilePath(ipath, "Klimt/Klimt.pgm");
vpImageIo::read(I, filename);
} else {
}
else {
filename = opt_ppath;
vpImageIo::read(I, filename);
printf("Image \"%s\" read successfully\n", filename.c_str());
Expand Down Expand Up @@ -579,7 +620,8 @@ int main(int argc, const char *argv[])
if (opt_ppath.empty()) {
filename = vpIoTools::createFilePath(ipath, "Klimt/Klimt.ppm");
vpImageIo::read(I_rgb, filename);
} else {
}
else {
filename = opt_ppath;
vpImageIo::read(I_rgb, filename);
printf("Image \"%s\" read successfully\n", filename.c_str());
Expand Down Expand Up @@ -612,7 +654,8 @@ int main(int argc, const char *argv[])
#endif
}

} catch (const vpException &e) {
}
catch (const vpException &e) {
std::cerr << "Catch an exception: " << e.what() << std::endl;
return EXIT_FAILURE;
}
Expand Down

0 comments on commit 7e495db

Please sign in to comment.