You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于OpenCV for Android的桌游地图六边形网格检测问题求助

Hey there! Let's work through this hexagon detection problem you're hitting with OpenCV on Android. I’ve messed around with similar grid-based detection tasks before, so here are some practical, tried-and-tested approaches to catch all those hexagons—even the ones split up by rivers or roads:

1. Ditch the single Value channel, use multi-channel thresholding

Relying solely on the HSV Value channel makes it easy for rivers/roads (which often have similar brightness to hex edges) to break your detection. Instead, try these alternatives:

  • Adaptive grayscale thresholding: Convert your image to grayscale first, then use adaptive thresholding that adjusts based on local pixel values. This works way better for textured maps with uneven lighting or overlapping elements:
Mat gray = new Mat();
Imgproc.cvtColor(yourSourceMat, gray, Imgproc.COLOR_BGR2GRAY);
Mat adaptiveThresh = new Mat();
// Adjust the block size (11) and C value (2) based on your map's scale
Imgproc.adaptiveThreshold(gray, adaptiveThresh, 255, Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C, Imgproc.THRESH_BINARY_INV, 11, 2);
  • HSV multi-channel filtering: If you still want to use HSV, combine thresholding on Hue (to target the hex base colors) and Saturation (to separate solid hex areas from low-saturation roads/rivers), then merge those masks with your Value channel threshold using bitwise operations. This weeds out the interfering elements more effectively.
2. Smart morphological operations (not just brute-force dilation)

Simple dilation to "thicken" boundaries often merges adjacent hexagons or creates messy noise. Instead, use targeted morphological steps:

  • Opening first: Use a small kernel to run an opening operation (erosion followed by dilation) to strip away tiny, unwanted contours from roads/rivers:
Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3, 3));
Imgproc.morphologyEx(yourThresholdMat, yourThresholdMat, Imgproc.MORPH_OPEN, kernel);
  • Closing to fix gaps: Follow up with a closing operation (dilation followed by erosion) to fill in the small gaps inside hexagons caused by rivers cutting through them. This helps reconnect broken contour segments:
Imgproc.morphologyEx(yourThresholdMat, yourThresholdMat, Imgproc.MORPH_CLOSE, kernel);

Tweak the kernel size (try 5x5 if your hexagons are larger) to match your map's scale.

3. Filter contours using geometric hexagon traits

Once you extract contours, you need to sift out the ones that actually look like hexagons:

  • Approximate polygons: For each contour, use approxPolyDP to simplify the shape, then check if the simplified polygon has exactly 6 sides:
List<MatOfPoint> contours = new ArrayList<>();
Imgproc.findContours(yourProcessedMat, contours, new Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);

for (MatOfPoint contour : contours) {
    MatOfPoint2f contour2f = new MatOfPoint2f(contour.toArray());
    // Epsilon controls approximation tightness—adjust based on your map
    double epsilon = 0.04 * Imgproc.arcLength(contour2f, true);
    MatOfPoint2f approxShape = new MatOfPoint2f();
    Imgproc.approxPolyDP(contour2f, approxShape, epsilon, true);
    
    if (approxShape.rows() == 6) {
        // This is a hexagon! Draw or process it
        Imgproc.drawContours(yourSourceMat, Collections.singletonList(new MatOfPoint(approxShape.toArray())), -1, new Scalar(0, 255, 0), 2);
    }
}
  • Add extra filters: Throw in checks for contour area (to skip tiny noise) or aspect ratio (to rule out non-hex shapes) if you still get false positives.
4. Pre-segment hexagon base colors first

If your game map uses consistent base colors for hexagons (even if they vary slightly), start by isolating those colors:

  • Define HSV ranges for each hex base color, then create a mask that only keeps those regions:
Mat hsv = new Mat();
Imgproc.cvtColor(yourSourceMat, hsv, Imgproc.COLOR_BGR2HSV);
// Adjust these scalar values to match your hex colors
Scalar lowerHexColor = new Scalar(30, 50, 50);
Scalar upperHexColor = new Scalar(60, 255, 255);
Mat hexMask = new Mat();
Core.inRange(hsv, lowerHexColor, upperHexColor, hexMask);

Use this mask to crop out just the hexagon areas from the original image, then run your contour detection on the masked result. This eliminates roads/rivers entirely from the detection pipeline.


内容的提问来源于stack exchange,提问作者tommy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:25:11