扫描靶纸得分
Scan shoting target paper for score
我正在尝试编写一个桌面应用程序来计算射击目标范围纸的分数。
经过研究,找到一些文章可以提供帮助,但仍然是如何使用 openCv 或 emguCv 的问题,我擅长 C#,但 C++ 需要时间来学习它。
另一个问题,检测射击目标重叠弹孔的最佳方法是什么?
喜欢这张图片
图片如上。在环 7 和环 8 中有两个重叠的弹孔。在这种情况下,只需执行腐蚀即可轻松解决。
但是,在圆圈几乎完全重叠的情况下,我不知道如何识别它们。
一些链接可以提供帮助:
您可以按照以下步骤隔离重叠的项目符号:
- 将子弹与图像的其余部分隔离开来
- 在子弹上应用开口(腐蚀然后膨胀)
- 计算每个白色像素到最近的黑色像素的距离
- 应用阈值
C++代码:
cv::Mat preprocess(const cv::Mat image) {
display(image, "Original");
// Color thresholds
cv::Scalar minColor(141, 0, 0);
cv::Scalar maxColor(255, 255, 124);
cv::Mat filtered;
// Isolate the interesting range of colors
cv::inRange(image, minColor, maxColor, filtered);
filtered.convertTo(filtered, CV_8U);
// Apply opening (erode then dilate)
cv::Mat opening;
cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
cv::morphologyEx(filtered, opening, cv::MORPH_OPEN, kernel, cv::Point(-1,-1), 2);
// Compute the distance to the closest zero pixel (euclidian)
cv::Mat distance;
cv::distanceTransform(opening, distance, CV_DIST_L2, 5);
cv::normalize(distance, distance, 0, 1.0, cv::NORM_MINMAX);
display(distance, "Distance");
// Thresholding using the longest distance
double min, max;
cv::minMaxLoc(distance, &min, &max);
cv::Mat thresholded;
cv::threshold(distance, thresholded, 0.7 * max, 255, CV_THRESH_BINARY);
thresholded.convertTo(thresholded, CV_8U);
// Find connected components
cv::Mat labels;
int nbLabels = cv::connectedComponents(thresholded, labels);
// Assign a random color to each label
vector<int> colors(nbLabels, 0);
for (int label = 1; label < nbLabels; ++label) {
colors[label] = rand() & 255;
}
cv::Mat result(distance.size(), CV_8U);
for (int r = 0; r < result.rows; ++r) {
for (int c = 0; c < result.cols; ++c) {
int label = labels.at<int>(r, c);
result.at<uchar>(r, c) = colors[label];
}
}
display(result, "Labels");
return result;
}
您可以通过两种方式完成任务。
- 更简单的方法是减去图像。拍摄理想的目标图像,并在每次命中后或最后在完成整个拍摄后将其与目标图像相减。
- 另一种方法是分离颜色。如果子弹的颜色是蓝色,那么可以使用inRange函数过滤掉颜色。您甚至可以制作一个包含不同颜色项目符号的库,以便用户可以从选项中进行选择。我最近在 C# 中完成了类似的项目。有关详细信息,请联系我的电子邮件。(rajkumarm704@gmail.com)
我正在尝试编写一个桌面应用程序来计算射击目标范围纸的分数。
经过研究,找到一些文章可以提供帮助,但仍然是如何使用 openCv 或 emguCv 的问题,我擅长 C#,但 C++ 需要时间来学习它。
另一个问题,检测射击目标重叠弹孔的最佳方法是什么?
喜欢这张图片
但是,在圆圈几乎完全重叠的情况下,我不知道如何识别它们。
一些链接可以提供帮助:
您可以按照以下步骤隔离重叠的项目符号:
- 将子弹与图像的其余部分隔离开来
- 在子弹上应用开口(腐蚀然后膨胀)
- 计算每个白色像素到最近的黑色像素的距离
- 应用阈值
C++代码:
cv::Mat preprocess(const cv::Mat image) {
display(image, "Original");
// Color thresholds
cv::Scalar minColor(141, 0, 0);
cv::Scalar maxColor(255, 255, 124);
cv::Mat filtered;
// Isolate the interesting range of colors
cv::inRange(image, minColor, maxColor, filtered);
filtered.convertTo(filtered, CV_8U);
// Apply opening (erode then dilate)
cv::Mat opening;
cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
cv::morphologyEx(filtered, opening, cv::MORPH_OPEN, kernel, cv::Point(-1,-1), 2);
// Compute the distance to the closest zero pixel (euclidian)
cv::Mat distance;
cv::distanceTransform(opening, distance, CV_DIST_L2, 5);
cv::normalize(distance, distance, 0, 1.0, cv::NORM_MINMAX);
display(distance, "Distance");
// Thresholding using the longest distance
double min, max;
cv::minMaxLoc(distance, &min, &max);
cv::Mat thresholded;
cv::threshold(distance, thresholded, 0.7 * max, 255, CV_THRESH_BINARY);
thresholded.convertTo(thresholded, CV_8U);
// Find connected components
cv::Mat labels;
int nbLabels = cv::connectedComponents(thresholded, labels);
// Assign a random color to each label
vector<int> colors(nbLabels, 0);
for (int label = 1; label < nbLabels; ++label) {
colors[label] = rand() & 255;
}
cv::Mat result(distance.size(), CV_8U);
for (int r = 0; r < result.rows; ++r) {
for (int c = 0; c < result.cols; ++c) {
int label = labels.at<int>(r, c);
result.at<uchar>(r, c) = colors[label];
}
}
display(result, "Labels");
return result;
}
您可以通过两种方式完成任务。
- 更简单的方法是减去图像。拍摄理想的目标图像,并在每次命中后或最后在完成整个拍摄后将其与目标图像相减。
- 另一种方法是分离颜色。如果子弹的颜色是蓝色,那么可以使用inRange函数过滤掉颜色。您甚至可以制作一个包含不同颜色项目符号的库,以便用户可以从选项中进行选择。我最近在 C# 中完成了类似的项目。有关详细信息,请联系我的电子邮件。(rajkumarm704@gmail.com)