OpenCV имеет функцию, называемую InRange
(в C++ это будет cv2.InRange
, Java-Core.InRange
). В этой функции вы предоставляете два объекта Scalar
: один начинает цвет BGR диапазона цветов, другой - это конец. Он вернет вам маску белых пикселей: белый цвет находится в диапазоне, черный - нет. Дополнительная информация HERE. Я бы рекомендовал вам позвонить InRange
до HoughCircles
, было бы легче определить, какие объекты зеленых кругов, а не зеленые круги.
Я опробовал этот метод для решения вашей проблемы:
- Во-первых, я выполняю функцию InRange с началом HSV значения
Scalar(37, 38, 70)
и заканчивая Scalar(85, 255, 200)
. Обратите внимание, что вы не добавляете значения RGB или BGR в Scalar, это цвет HSV (от H (0-180), S (0-255), V (0-255), как указано в THIS)):
- во-вторых, я выполняю Algorythm HoughCircles, как вы в вашем коде:
Как вы видите, есть один круг, где Шоул d не будет, также круги могут отличаться по размеру на обеих картинках. Я настоятельно рекомендую вам играть со значениями функции InRange, чтобы улучшить выбор цвета, сделать круги круглыми и более совершенными, и HoughCircles, чтобы избежать случайных и ненужных кругов, когда я получил один из них в середине последнего изображения. Кроме того, я предложил бы вам экспериментировать с Canny algorythm (Canny edge detector), чтобы очистить центры этих объектов, возможно, ваши результаты улучшатся.
код в Java, но вы должны легко понять, как ваше беспокойство в основном функция InRange:
Mat src = new Mat();
Mat circles = new Mat();
Mat result;
Utils.bitmapToMat(Image, src);
Imgproc.cvtColor(src, src, Imgproc.COLOR_BGR2HSV);
Core.inRange(src, new Scalar(37, 38, 70), new Scalar(85, 255, 200), src);
Imgproc.HoughCircles(src, circles, Imgproc.CV_HOUGH_GRADIENT, 2, 30, 100, 22, 10, 17);
result = new Mat(src.rows(), src.cols(), CvType.CV_8UC1, new Scalar(0,0,0));
for (int i = 0; i < circles.cols(); i++)
{
double[] circle = circles.get(0, i);
if (circle == null) break;
Point center = new Point(Math.round(circle[0]), Math.round(circle[1]));
int radius = (int)Math.round(circle[2]);
Imgproc.circle(result, center, radius, new Scalar(255, 0, 0));
}
return result;
В конце концов, это даже алгоритм с нужными значениями не может быть совершенным. Я думаю, что можно получить действительно большие или идеальные результаты с правильными значениями (у меня, к сожалению, не было много времени, чтобы узнать их, поэтому я оставляю это вам), но если вам нужен идеальный результат, я бы предложил вам экспериментировать в более широком спектре. Например, вызов функции Canny на цветном изображении (например, вы предоставили) может дать вам очень точные контуры кругов и других объектов. Затем, например, вы можете выполнить функцию HoughCircles на этих контурах и иметь данные из них, очистить все пиксели за пределами кругов. Затем с помощью InRange вы можете проверить цвета кругов и отсортировать их ...Но это просто теоретическое. Попробуйте все, что приходит на ум. Это экспериментирование может дать вам более корректный результат, чем обновленный текущий. Удачи!
На самом деле, я думаю, что это может быть проще обнаружить в BGR, а не в HSV. Пробовали ли вы смотреть на отношение компонента Green к красному (или синему) компоненту обнаруженных дисков? – beaker
@beaker, это полная бессмыслица. BGR <-> Преобразование HSV полностью биективно. –
Я решил вашу проблему с кодом и примерами и отредактировал ответ. Не забудьте проверить! –