如何对角分割图像?

How to split images diagonally?

我有如下图片。我想对角线分割它们,可能使用图像的质心或获取边界的角度 rect/ellipse 并沿其切割。

蓝色和绿色代表不同的轮廓,在实践中,这些将被二进制阈值处理,所以所有颜色看起来都一样。

我可以使用列表切片水平或垂直切割图像:

eg img_split=img[:50%,:]

我如何在 OpenCV 中对角线 Python/Numpy?

图片:

拆分样本:

如果您只想切割,可以使用fillPoly功能来帮助您切割任何多边形。在下面的代码中,我只是手动给出了多边形点。

注意:如果您希望程序检测到这些点,对于第一张图像很容易,因为对象具有不同的颜色。但是对于第二张图片我不知道该怎么做。

结果:

代码:

注意:我的环境是基于C++的,这就是我使用它的原因,但它应该很容易转换。

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc/imgproc.hpp"

using namespace cv;

int main()
{


    cv::Mat img = cv::imread("/ur/image/directory/image.png");
    imshow("original",img);

    cv::Point corners[1][4];
    corners[0][0] = Point( 0, 0 );
    corners[0][1] = Point( img.cols/2, img.rows/2 );
    corners[0][2] = Point( img.cols, img.rows );
    corners[0][3] = Point( img.cols, 0 );

    const Point* corner_list[1] = { corners[0] };

    int num_points = 4;
    int num_polygons = 1;
    int line_type = 8;

    cv::Mat mask = cv::Mat::zeros(img.rows, img.cols, CV_8UC1);
    cv::fillPoly( mask, corner_list, &num_points, num_polygons, cv::Scalar( 255, 255, 255 ),  line_type);
    cv::Mat result(img.size(), img.type(), cv::Scalar(255, 255, 255));
    img.copyTo(result, mask);

    imshow("Output",result);
    cv::waitKey(0);
    return 0;
}

我基本上遵循你的想法:

  • 图像的逆二进制阈值(假设:纯白色背景上的不同对象)。
  • 寻找外部轮廓(假设:只有一个object/contour)。
  • 找到最小面积的旋转矩形。
  • 计算质心。
  • 利用质心和旋转角度,计算两个边缘点,其中"diagonal"将图像分成两部分。
  • 使用蒙版和"anti-mask"为图像部分和分割图像生成蒙版。

完整代码如下:

import cv2
import numpy as np
from skimage import io              # Only needed for web reading images


def process(img_url):

    # Web read image
    img = cv2.cvtColor(io.imread(img_url), cv2.COLOR_RGB2BGR)
    img_c = img.copy()

    # Inverse binary threshold grayscale version of image
    # Assumption: plain white background
    img_thr = cv2.threshold(cv2.cvtColor(img, cv2.COLOR_BGR2GRAY), 248, 255, cv2.THRESH_BINARY_INV)[1]

    # Find external contour
    # Assumption: only one object/contour
    cnts = cv2.findContours(img_thr, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    cnts = cnts[0] if len(cnts) == 2 else cnts[1]

    # Find rotated rectangle of the minimum area
    rect = cv2.minAreaRect(cnts[0])
    rect_pts = np.int0(cv2.boxPoints(rect))

    # Calculate centroid
    cent = np.int0((rect_pts[0] + rect_pts[2]) / 2)

    # Calculate tangent of rotation angle
    alpha = rect[2]
    if np.abs(alpha) > 45:
        alpha += 90
    tan_alpha = np.tan(np.deg2rad(alpha))

    # Calculate first edge point
    x0 = np.int32(cent[0] - cent[1] / tan_alpha)
    if x0 < 0:
        x0 = 0
        y0 = np.int32(-cent[0] * tan_alpha + cent[1])
    else:
        y0 = 0

    # Calculate second edge point
    x1 = np.int32(cent[0] + (img.shape[0] - cent[1]) / tan_alpha)
    if x1 > img.shape[1]:
        x1 = img.shape[1]
        y1 = np.int32((x1 - cent[0]) * tan_alpha + cent[1])
    else:
        y1 = img.shape[0]

    # Generate mask for cutting
    # Assumption: Image is sufficient large
    mask = np.zeros_like(img_thr)
    mask = cv2.line(mask, (x0, y0), (x1, y1), 255, 1)
    cv2.floodFill(mask, None, (cent[0] - 5, cent[1] - 5), 255)

    # Split image
    mask3 = np.repeat(np.expand_dims(mask, 2), 3, 2)
    img1 = ~mask3 + cv2.bitwise_and(img_c, img_c, mask=mask)
    img2 = mask3 + cv2.bitwise_and(img_c, img_c, mask=255-mask)

    # Debug output
    img = cv2.line(img, (x0, y0), (x1, y1), (0, 0, 255), 2)
    img = cv2.drawContours(img, [rect_pts], -1, (128, 128, 128), 2)
    img = cv2.circle(img, tuple(cent), 5, (255, 0, 0), 4)

    cv2.imshow('img', img)
    cv2.imshow('img1', img1)
    cv2.imshow('img2', img2)
    cv2.waitKey(0)


img_urls = [
    'https://i.stack.imgur.com/suzjF.png',
    'https://i.stack.imgur.com/Rl2WN.png'
]

for i in img_urls:
    process(i)

cv2.destroyAllWindows()

结果如下(带有一些调试输出):

希望对您有所帮助!

----------------------------------------
System information
----------------------------------------
Platform:    Windows-10-10.0.16299-SP0
Python:      3.8.1
NumPy:       1.18.1
OpenCV:      4.2.0
----------------------------------------