This code’s purpose is to test if the function extracts the second-largest object in the image (the first is the background), the second-largest object is known by running the same function (checking by eye), so sample.object
is the result of running this function. which is not a good way to test functions, but since I can verify that it’s actually the largest by eye It’s ok.
Now when running this code, the eq
is false, (mats are not equal), so the function result mat is not the same as the disk mat (read from object.jpg
), my guessing is that when saving the image in .jpg
information is lost, so the function result mat is not the same as the disk mat.
extract_object.cpp
:
//
// Created by jamal on 5/1/2021.
//
#include <opencv2/opencv.hpp>
#include <impl/image_utils.hpp>
using namespace cv;
typedef std::tuple<int, int> size_g;
bool sortSizes(size_g a, size_g b) {
return std::get<1>(a) > std::get<1>(b);
}
int calculate_diameter(int x, int y) {
return (int) sqrt(pow(x, 2) + pow(y, 2));
}
image get_object_by_index(cimage frame, cimage stats, int index);
std::optional<image> ImageUtilsImpl::extract_object(const image &frame) {
image threshold;
adaptiveThreshold(frame, threshold, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 301, -7);
image labels;
image stats;
image centroids;
int nLabels = connectedComponentsWithStats(threshold, labels, stats, centroids, 8, CV_32S);
if (nLabels < 1) return {};
std::vector<size_g> sizes;
for (int label = 0; label < nLabels; ++label) {
int width = stats.at<int>(label, CC_STAT_WIDTH);
int height = stats.at<int>(label, CC_STAT_HEIGHT);
int diameter = calculate_diameter(width, height);
sizes.emplace_back(size_g(label, diameter));
}
// sort stats based on highest diameter = sqrt( (x)^2 + (y)^2 )
std::sort(sizes.begin(), sizes.end(), sortSizes);
// ignore index 0 since it's always the background (the main image)
int largestObjectIndex = std::get<0>(sizes[1]);
image object = get_object_by_index(frame, stats, largestObjectIndex);
return object;
}
image get_object_by_index(cimage frame, cimage stats, int index) {
int x = stats.at<int>(index, CC_STAT_LEFT);
int y = stats.at<int>(index, CC_STAT_TOP);
int h = stats.at<int>(index, CC_STAT_HEIGHT);
int w = stats.at<int>(index, CC_STAT_WIDTH);
Rect rect(x, y, w, h);
return frame(rect);
}
read.cpp
image ImageUtilsImpl::read(std::string filename) {
return cv::imread(filename, cv::IMREAD_GRAYSCALE);
}
test_extract_object.cpp
typedef cv::Mat image;
bool is_mat_eq(ImageUtils *utils, image im1, image im2) {
cv::Mat diff = im1 != im2;
utils->write("diff.jpg", diff);
bool eq = cv::countNonZero(diff) == 0;
return eq;
}
TEST_P(ExtractObjectFixture, ExtractsObjectCorrectly) {
ExtractObjectSample sample = GetParam();
auto imageUtils = this->getInjector()->get<ImageUtils *>();
std::optional<image> resultObject = imageUtils->extract_object(imageUtils->read(sample.mainImage));
ASSERT_TRUE(resultObject);
image object = *resultObject;
image sobject = imageUtils->read(sample.object);
EXPECT_EQ(object.rows, sobject.rows);
EXPECT_EQ(object.cols, sobject.cols);
std::string object_filename= this->generate_unique_file_name();
imageUtils->write(object_filename, sobject);
auto diskObject = imageUtils->read(object_filename);
bool eq = is_mat_eq(imageUtils, diskObject, sobject);
EXPECT_TRUE(eq);
}
diff.jpg
: