Skip to content

Commit

Permalink
Done first part
Browse files Browse the repository at this point in the history
  • Loading branch information
Konstantysz committed Nov 24, 2021
1 parent 19a86cf commit dce11c6
Show file tree
Hide file tree
Showing 8 changed files with 292 additions and 57 deletions.
21 changes: 21 additions & 0 deletions ImageAnalysis/ImageAnalysisUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,27 @@ namespace ImageAnalysis
{
namespace utils
{
std::array<int, 256> Histogram(const cv::Mat& input)
{
if (input.type() != CV_8UC1)
{
// TODO: Conversion to proper type
return std::array<int, 256>();
}

auto histogram = std::array<int, 256>();

for (int i = 0; i < input.rows; i++)
{
for (int j = 0; j < input.cols; j++)
{
histogram[(int)input.at<uchar>(i, j)]++;
}
}

return histogram;
}

void SingleConvolve(const cv::Mat& input, cv::Mat& output, const cv::Mat& kernel, const int& i, const int& j)
{
cv::Mat roi;
Expand Down
2 changes: 2 additions & 0 deletions ImageAnalysis/ImageAnalysisUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ namespace ImageAnalysis
std::chrono::steady_clock::time_point tic;
};

std::array<int, 256> Histogram(const cv::Mat& input);

void SingleConvolve(const cv::Mat& input, cv::Mat& output, const cv::Mat& kernel, const int& i, const int& j);

cv::Mat ConvolveZeroPad(const cv::Mat& input, const cv::Mat& kernel);
Expand Down
49 changes: 44 additions & 5 deletions ImageAnalysis/ImageAnalyzer.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,53 @@

namespace ImageAnalysis
{
//typedef std::pair<int, cv::Point2i> CircleParameters;
using CircleParameters = std::pair<int, cv::Point2i>;
struct Circle
{
Circle(int x, int y, int r, int votes) : x(x), y(y), radius(r)
{
float diameter = 2 * CV_PI * r;
probability = (r > 0) ? static_cast<float>(votes) / diameter : 0.F;
filtered = false;
}
float probability;
int x;
int y;
int radius;
bool filtered;
};

class ImageAnalyzer
{
public:
virtual cv::Mat GaussianBlur(const cv::Mat& input, const int& kernelSize, const double& sigma = 1.0) = 0;
virtual cv::Mat GaussianBlur(
const cv::Mat& input,
const int& kernelSize,
const double& sigma = 1.0
) = 0;

virtual cv::Mat LoGFilter(
const cv::Mat& input,
const int& kernelSize,
const double& sigma = 1.0
) = 0;

virtual cv::Mat OtsuThreshold(
const cv::Mat& input,
const int& thresholdValue
) = 0;
virtual cv::Mat BGR2Grayscale(const cv::Mat& input) = 0;
virtual cv::Mat Canny(const cv::Mat& input, float lowThresholdRatio = 0.05, float highThresholdRatio = 0.09) = 0;
virtual std::vector<CircleParameters> CircleHoughTransform(const cv::Mat& input, const int& lowRadiusThreshold, const int& highRadiusThreshold) = 0;

virtual cv::Mat Canny(
const cv::Mat& input,
const float& lowThresholdRatio = 0.05,
const float& highThresholdRatio = 0.09
) = 0;

virtual std::vector<Circle> CircleHoughTransform(
const cv::Mat& input,
const int& lowRadiusThreshold,
const int& highRadiusThreshold,
const int& minDistance
) = 0;
};
} // namespace ImageAnalysis
154 changes: 130 additions & 24 deletions ImageAnalysis/ImageAnalyzerSingleThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@

namespace ImageAnalysis
{
cv::Mat ImageAnalyzerSingleThread::GaussianBlur(const cv::Mat& input, const int& kernelSize, const double& sigma)
cv::Mat ImageAnalyzerSingleThread::GaussianBlur(
const cv::Mat& input,
const int& kernelSize,
const double& sigma
)
{
// Generate kernel
cv::Mat kernel = ImageAnalysis::utils::GaussianKernelGenerator(kernelSize, sigma);
Expand All @@ -26,6 +30,66 @@ namespace ImageAnalysis
return output;
}

cv::Mat ImageAnalyzerSingleThread::LoGFilter(
const cv::Mat& input,
const int& kernelSize,
const double& sigma
)
{
return cv::Mat();
}

cv::Mat ImageAnalyzerSingleThread::OtsuThreshold(
const cv::Mat& input,
const int& thresholdValue
)
{
int N = input.rows * input.cols;
auto histogram = utils::Histogram(input);

double sum = 0;
for (int v = 0; v < 256; v++)
{
sum += v * histogram[v];
}

double q1 = 0;
double q2 = 0;
double u1 = 0;
double u2 = 0;
double sumB = 0;
double varMax = 0;
int threshold = 0;
for (int v = 0; v < 256; v++)
{
q1 += histogram[v];
if (q1 == 0) continue;
q2 = N - q1;
sumB += v * histogram[v];
u1 = sumB / q1;
u2 = (sum - sumB) / q2;
double var = q1 * q2 * (u1 - u2) * (u1 - u2);

if (var > varMax)
{
threshold = v;
varMax = var;
}
}

cv::Mat output;
input.copyTo(output);
for (int i = 0; i < input.cols; i++)
{
for (int j = 0; j < input.rows; j++)
{
output.at<uchar>(j, i) = (output.at<uchar>(j, i) > threshold) ? 255 : 0;
}
}

return output;
}

cv::Mat ImageAnalyzerSingleThread::BGR2Grayscale(const cv::Mat& input)
{
if (input.channels() != 3) return input;
Expand Down Expand Up @@ -114,7 +178,11 @@ namespace ImageAnalysis
return grayscaleOutput;
}

cv::Mat ImageAnalyzerSingleThread::Canny(const cv::Mat& input, float lowThresholdRatio, float highThresholdRatio)
cv::Mat ImageAnalyzerSingleThread::Canny(
const cv::Mat& input,
const float& lowThresholdRatio,
const float& highThresholdRatio
)
{
cv::Mat imgGrayscale;
if (input.channels() != 1)
Expand Down Expand Up @@ -147,13 +215,23 @@ namespace ImageAnalysis
return cannyEdges;
}

std::vector<CircleParameters> ImageAnalyzerSingleThread::CircleHoughTransform(const cv::Mat& input, const int& lowRadiusThreshold, const int& highRadiusThreshold)
std::vector<Circle> ImageAnalyzerSingleThread::CircleHoughTransform(
const cv::Mat& input,
const int& lowRadiusThreshold,
const int& highRadiusThreshold,
const int& minDistance
)
{
auto circles = std::vector<CircleParameters>();
auto circles = std::vector<Circle>();

cv::Mat accumulator = cv::Mat::zeros(input.size(), CV_32F);
auto accumulator = std::vector<cv::Mat>(highRadiusThreshold - lowRadiusThreshold + 1);
for (auto& layer : accumulator)
{
layer = cv::Mat::zeros(input.size(), CV_32S);
}

for (int r = lowRadiusThreshold; r <= highRadiusThreshold; r++)
//!< Voting
for (size_t r = lowRadiusThreshold; r <= highRadiusThreshold; r++)
{
for (int t = 0; t < 360; t++)
{
Expand All @@ -167,34 +245,62 @@ namespace ImageAnalysis
int a = i - r * cos(t * CV_PI / 180);
if (a > 0 && a < input.cols && b > 0 && b < input.rows)
{
accumulator.at<float>(b, a) += 1.F;
accumulator[r - static_cast<size_t>(lowRadiusThreshold)].at<int>(b, a)++;
}
}
}
}
}
}

//for (int i = 0; i < accumulator.cols; i++)
//{
// for (int j = 0; j < accumulator.rows; j++)
// {
// if (accumulator.at<float>(j, i) > 2 * CV_PI * r * 0.9)
// {
// circles.push_back(std::make_pair(r, cv::Point2i(i, j)));
// }
// }
//}
//!< Extracting circles data
for (size_t r = lowRadiusThreshold; r <= highRadiusThreshold; r++)
{
size_t id = r - static_cast<size_t>(lowRadiusThreshold);
int minimalVotes = 2 * CV_PI * r * 0.9;
for (int i = 0; i < accumulator[id].cols; i++)
{
for (int j = 0; j < accumulator[id].rows; j++)
{
if (accumulator[id].at<int>(j, i) > minimalVotes)
{
circles.push_back(Circle(i, j, r, accumulator[id].at<int>(j, i)));
}
}
}
}

double min, max;
cv::minMaxLoc(accumulator, &min, &max);
accumulator /= max;
accumulator *= 255;
//!< Circles filtration to remove repeating circles
std::vector<Circle> resultCircles;
for (auto circle = circles.begin(); circle != circles.end(); ++circle)
{
if (!circle->filtered)
{
std::vector<Circle> neighbours;
neighbours.push_back(*circle);
circle->filtered = true;
for (auto otherCircle = circle; otherCircle != circles.end(); ++otherCircle)
{
int centerDistance = static_cast<int>(std::sqrt(
(circle->x - otherCircle->x) * (circle->x - otherCircle->x) + (circle->y - otherCircle->y) * (circle->y - otherCircle->y)
));
if (centerDistance < minDistance)
{
neighbours.push_back(*otherCircle);
otherCircle->filtered = true;
}
}

cv::Mat accumulator8u;
accumulator.convertTo(accumulator8u, CV_8U);
auto bestCircle = std::max_element(neighbours.begin(), neighbours.end(),
[](const Circle& a, const Circle& b)
{
return a.probability < b.probability;
});
resultCircles.push_back(*bestCircle);
}
}

return circles;
return resultCircles;
}

}
33 changes: 30 additions & 3 deletions ImageAnalysis/ImageAnalyzerSingleThread.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,36 @@ namespace ImageAnalysis
class ImageAnalyzerSingleThread : public ImageAnalyzer
{
public:
cv::Mat GaussianBlur(const cv::Mat& input, const int& kernelSize, const double& sigma = 1.0);
cv::Mat GaussianBlur(
const cv::Mat& input,
const int& kernelSize,
const double& sigma = 1.0
);

cv::Mat LoGFilter(
const cv::Mat& input,
const int& kernelSize,
const double& sigma = 1.0
);

cv::Mat OtsuThreshold(
const cv::Mat& input,
const int& thresholdValue
);

cv::Mat BGR2Grayscale(const cv::Mat& input);
cv::Mat Canny(const cv::Mat& input, float lowThresholdRatio = 0.05, float highThresholdRatio = 0.09);
std::vector<CircleParameters> CircleHoughTransform(const cv::Mat& input, const int& lowRadiusThreshold, const int& highRadiusThreshold);

cv::Mat Canny(
const cv::Mat& input,
const float& lowThresholdRatio = 0.05,
const float& highThresholdRatio = 0.09
);

std::vector<Circle> CircleHoughTransform(
const cv::Mat& input,
const int& lowRadiusThreshold,
const int& highRadiusThreshold,
const int& minDistance
);
};
} // namespace ImageAnalysis
1 change: 0 additions & 1 deletion ImageAnalysis/pch.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,4 @@
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>


#endif //PCH_H
Loading

0 comments on commit dce11c6

Please sign in to comment.