From 965f75049a14143f63675e704ccae7a0a6250730 Mon Sep 17 00:00:00 2001 From: Tavi Kohn Date: Thu, 13 Oct 2016 21:09:52 -0600 Subject: [PATCH 1/2] added contour sorting from left to right --- .../teamtators/vision/vision/FrameProcessor.kt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/main/java/org/teamtators/vision/vision/FrameProcessor.kt b/src/main/java/org/teamtators/vision/vision/FrameProcessor.kt index 6ca8399..8f00381 100644 --- a/src/main/java/org/teamtators/vision/vision/FrameProcessor.kt +++ b/src/main/java/org/teamtators/vision/vision/FrameProcessor.kt @@ -124,6 +124,8 @@ class FrameProcessor @Inject constructor( && it.solidity <= config.maxSolidity } + + // Find largest contour by area val trackingContour = filteredContours.maxBy { it.area } @@ -219,4 +221,20 @@ class FrameProcessor @Inject constructor( // mat.drawLine(Point(0.0, center.y), Point(width, center.y), overlayColor) mat.drawLine(Point(center.x, 0.0), Point(center.x, height), overlayColor) } + + private fun sortLeftToRight(contours: List) { + Collections.sort(contours, {info1: ContourInfo, info2: ContourInfo -> info1.center.x.compareTo(info2.center.x)}); + } + + private fun sortRightToLeft(contours: List) { + Collections.sort(contours, {info1: ContourInfo, info2: ContourInfo -> - info1.center.x.compareTo(info2.center.x)}); + } + + private fun sortTopToBottom(contours: List) { + Collections.sort(contours, {info1: ContourInfo, info2: ContourInfo -> - info1.center.y.compareTo(info2.center.x)}); + } + + private fun sortBottomToTop(contours: List) { + Collections.sort(contours, {info1: ContourInfo, info2: ContourInfo -> info1.center.y.compareTo(info2.center.x)}); + } } \ No newline at end of file From e7aff9fd5164f458cde18e251e59a60367547039 Mon Sep 17 00:00:00 2001 From: Tavi Kohn Date: Sun, 16 Oct 2016 18:32:28 -0600 Subject: [PATCH 2/2] Added basic solution for fluctuating max contour --- config.yml | 2 +- .../org/teamtators/vision/config/Config.kt | 2 +- .../vision/vision/FrameProcessor.kt | 129 +++++++++--------- 3 files changed, 70 insertions(+), 63 deletions(-) diff --git a/config.yml b/config.yml index 392c0ea..a0c5e7e 100644 --- a/config.yml +++ b/config.yml @@ -27,7 +27,7 @@ vision: maxArea: 10000 minSolidity: 0.0 maxSolidity: 1.0 - + maxAreaDifference: 50 #Maximum difference in area between largest contours to arcLengthPercentage: 0.01 # fieldOfView: [62.2, 48.8] # RPI camera FOV diff --git a/src/main/java/org/teamtators/vision/config/Config.kt b/src/main/java/org/teamtators/vision/config/Config.kt index a6c0744..74ce8dc 100644 --- a/src/main/java/org/teamtators/vision/config/Config.kt +++ b/src/main/java/org/teamtators/vision/config/Config.kt @@ -34,7 +34,7 @@ class VisionConfig { var maxArea: Int = 100000 var minSolidity: Double = 0.0 var maxSolidity: Double = 1.0 - + var maxAreaDifference: Int = 50 var arcLengthPercentage: Double = 0.01 var fieldOfView: Size = Size(62.2, 48.8) diff --git a/src/main/java/org/teamtators/vision/vision/FrameProcessor.kt b/src/main/java/org/teamtators/vision/vision/FrameProcessor.kt index 8f00381..4a1b467 100644 --- a/src/main/java/org/teamtators/vision/vision/FrameProcessor.kt +++ b/src/main/java/org/teamtators/vision/vision/FrameProcessor.kt @@ -124,10 +124,17 @@ class FrameProcessor @Inject constructor( && it.solidity <= config.maxSolidity } - - - // Find largest contour by area - val trackingContour = filteredContours.maxBy { it.area } + val trackingContour: ContourInfo?; + if (contours.size >= 2) { + trackingContour = if (Math.abs(contours[0].area - contours[1].area) < config.maxAreaDifference) { + contours[0]; + } else { + // Find largest contour by area + contours.maxBy { it.area } + } + } else { + trackingContour = contours.maxBy { it.area } + } val drawStart = System.nanoTime() // Draw all contours, with the largest one in a larger thickness @@ -163,78 +170,78 @@ class FrameProcessor @Inject constructor( var newAngle: Double? = null if (trackingContour != null) { val center = trackingContour.center - val height = inputMat.height() - val width = inputMat.width() - target = center + val height = inputMat.height() + val width = inputMat.width() + target = center - distance = config.distancePoly.calculate(center.y / height.toDouble()) + distance = config.distancePoly.calculate(center.y / height.toDouble()) // val widthInches = distance * Math.tan(config.fieldOfView.width.toRadians() / 2) * 2 // val offsetInches = (center.x / width - .5) * widthInches // offsetAngle = Math.atan2(offsetInches, distance).toDegrees() + config.horizontalAngleOffset - offsetAngle = (center.x / width - 0.5) * config.fieldOfView.width - newAngle = captureData.turretAngle + offsetAngle - } - val calculateEnd = System.nanoTime() - - if (_config.profile) { - val scale = 1 - val thresholdTime = (erodeStart - thresholdStart) / scale - val erodeTime = (contoursStart - erodeStart) / scale - val contoursTime = (filterContoursStart - contoursStart) / scale - val filterContoursTime = (drawStart - filterContoursStart) / scale - val drawTime = (calculateStart - drawStart) / scale - val calculateTime = (calculateEnd - calculateStart) / scale - val totalTime = (calculateEnd - erodeStart) / scale - logger.trace("threshold: {}, erode: {}, contours: {}, filter: {}, draw: {}, calculate: {}, total: {}", - thresholdTime, erodeTime, contoursTime, filterContoursTime, drawTime, calculateTime, totalTime) - } + offsetAngle = (center.x / width - 0.5) * config.fieldOfView.width + newAngle = captureData.turretAngle + offsetAngle + } + val calculateEnd = System.nanoTime() + + if (_config.profile) { + val scale = 1 + val thresholdTime = (erodeStart - thresholdStart) / scale + val erodeTime = (contoursStart - erodeStart) / scale + val contoursTime = (filterContoursStart - contoursStart) / scale + val filterContoursTime = (drawStart - filterContoursStart) / scale + val drawTime = (calculateStart - drawStart) / scale + val calculateTime = (calculateEnd - calculateStart) / scale + val totalTime = (calculateEnd - erodeStart) / scale + logger.trace("threshold: {}, erode: {}, contours: {}, filter: {}, draw: {}, calculate: {}, total: {}", + thresholdTime, erodeTime, contoursTime, filterContoursTime, drawTime, calculateTime, totalTime) + } - return ProcessResult(displayMat, target, distance, offsetAngle, newAngle) - } + return ProcessResult(displayMat, target, distance, offsetAngle, newAngle) + } - private fun drawContour(color: Scalar, contour: ContourInfo, thickness: Int) { - if (config.debug) - displayMat.drawContour(contour.contour, color, thickness) - displayMat.drawRotatedRect(contour.minAreaRect, color = color, thickness = thickness) - displayMat.drawCircle(contour.center, 2, color) + private fun drawContour(color: Scalar, contour: ContourInfo, thickness: Int) { + if (config.debug) + displayMat.drawContour(contour.contour, color, thickness) + displayMat.drawRotatedRect(contour.minAreaRect, color = color, thickness = thickness) + displayMat.drawCircle(contour.center, 2, color) - val fontScale = 0.3 + val fontScale = 0.3 - val str1 = String.format("area: %.0f", contour.rectArea); - val str1Size = Imgproc.getTextSize(str1, fontFace, fontScale, 1, null) - displayMat.drawText(str1, contour.center + Point(-str1Size.width / 2, -str1Size.height / 2), - fontFace = fontFace, fontScale = fontScale, color = color) + val str1 = String.format("area: %.0f", contour.rectArea); + val str1Size = Imgproc.getTextSize(str1, fontFace, fontScale, 1, null) + displayMat.drawText(str1, contour.center + Point(-str1Size.width / 2, -str1Size.height / 2), + fontFace = fontFace, fontScale = fontScale, color = color) - val str2 = String.format("solidity: %.4f", contour.solidity); - val str2Size = Imgproc.getTextSize(str2, fontFace, fontScale, 1, null) - displayMat.drawText(str2, contour.center + Point(-str1Size.width / 2, str2Size.height / 2), - fontFace = fontFace, fontScale = fontScale, color = color) - } + val str2 = String.format("solidity: %.4f", contour.solidity); + val str2Size = Imgproc.getTextSize(str2, fontFace, fontScale, 1, null) + displayMat.drawText(str2, contour.center + Point(-str1Size.width / 2, str2Size.height / 2), + fontFace = fontFace, fontScale = fontScale, color = color) + } - private fun drawCrosshair(mat: Mat) { - val center = mat.size().toPoint() / 2.0 + private fun drawCrosshair(mat: Mat) { + val center = mat.size().toPoint() / 2.0 // val width = mat.size().width - val height = mat.size().height - mat.drawCenterRect(center, 25, 25, overlayColor) //to be replaced with corrected targeting values + val height = mat.size().height + mat.drawCenterRect(center, 25, 25, overlayColor) //to be replaced with corrected targeting values // mat.drawLine(Point(0.0, center.y), Point(width, center.y), overlayColor) - mat.drawLine(Point(center.x, 0.0), Point(center.x, height), overlayColor) - } + mat.drawLine(Point(center.x, 0.0), Point(center.x, height), overlayColor) + } - private fun sortLeftToRight(contours: List) { - Collections.sort(contours, {info1: ContourInfo, info2: ContourInfo -> info1.center.x.compareTo(info2.center.x)}); - } + private fun sortLeftToRight(contours: List) { + Collections.sort(contours, { info1: ContourInfo, info2: ContourInfo -> info1.center.x.compareTo(info2.center.x) }); + } - private fun sortRightToLeft(contours: List) { - Collections.sort(contours, {info1: ContourInfo, info2: ContourInfo -> - info1.center.x.compareTo(info2.center.x)}); - } + private fun sortRightToLeft(contours: List) { + Collections.sort(contours, { info1: ContourInfo, info2: ContourInfo -> -info1.center.x.compareTo(info2.center.x) }); + } - private fun sortTopToBottom(contours: List) { - Collections.sort(contours, {info1: ContourInfo, info2: ContourInfo -> - info1.center.y.compareTo(info2.center.x)}); - } + private fun sortTopToBottom(contours: List) { + Collections.sort(contours, { info1: ContourInfo, info2: ContourInfo -> -info1.center.y.compareTo(info2.center.x) }); + } - private fun sortBottomToTop(contours: List) { - Collections.sort(contours, {info1: ContourInfo, info2: ContourInfo -> info1.center.y.compareTo(info2.center.x)}); - } -} \ No newline at end of file + private fun sortBottomToTop(contours: List) { + Collections.sort(contours, { info1: ContourInfo, info2: ContourInfo -> info1.center.y.compareTo(info2.center.x) }); + } + } \ No newline at end of file