轮廓的所有矩求零

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了轮廓的所有矩求零相关的知识,希望对你有一定的参考价值。

我正在尝试拍摄像这样的图像,只包含灰度图像:

“多维数据集的灰度图像”

然后我要检索所述图像的轮廓并将其保存到.npy文件,逐层迭代直到图像不再存在。不幸的是,虽然合成轮廓为valid,但它们的合成矩为零。

为了处理图像周围的黑色空间,我实施了一种基本算法来裁剪所有空白空间:检索图像中任何空间的所有轮廓,然后裁剪为所述轮廓的x和y坐标。该算法在名为FrontImage的类中实现,如下所示:

class FrontImage:
    def __init__(self, img, lh):
        self.image = img
        self.layer_height = lh
        self.objs = self.getObjs()
        self.extrema = self.getExtrema()

    # gets the list of "objects" (read: contours) in the image
    def getObjs(self):
        # canny edge
        edged = cv2.Canny(self.image.copy(), 30, 200)

        # get contours from edged image
        cnts, hier = cv2.findContours(edged.copy(), \
                                      cv2.RETR_EXTERNAL, \
                                      cv2.CHAIN_APPROX_NONE)

        if (cnts is not None) and (len(cnts) > 0):
            # sort by area [for no real reason]
            cnts = sorted(cnts, key=cv2.contourArea)

            # return final list of objects
            return [DetectedObject(c) for c in cnts]

    # retrieves the extrema for later cropping
    def getExtrema(self):
        # get list of all extrema from all objects
        left_ext = [obj.extrema()[0] for obj in self.objs]
        right_ext = [obj.extrema()[1] for obj in self.objs]
        top_ext = [obj.extrema()[2] for obj in self.objs]
        bottom_ext = [obj.extrema()[3] for obj in self.objs]

        # sort by greatest values in respective directions
        max_x_ext = sorted(right_ext, key=lambda e: e[0])[-1]
        min_x_ext = sorted(left_ext, key=lambda e: e[0])[0]
        max_y_ext = sorted(top_ext, key=lambda e: e[1])[0]
        min_y_ext = sorted(bottom_ext, key=lambda e: e[1])[-1]

        return (max_x_ext, min_x_ext, max_y_ext, min_y_ext)

    # gets the xy size of the image
    def size(self):
        x_size = self.extrema[0][0] - self.extrema[1][0]
        y_size = int(np.floor((self.extrema[3][1] - self.extrema[2][1]) / self.layer_height))
        return (x_size, y_size)

    # crops the image based on extrema bounds and "height" to remove
    def crop(self, layers):
        # int(np.floor(()) converts it to a consistently "underapproximated" integer
        return FrontImage(self.image[int(np.floor(self.extrema[2][1]+self.layer_height*layers)):\
                                     self.extrema[3][1], \
                                     self.extrema[1][0]:self.extrema[0][0]], self.layer_height)

与这些极值有关的极值和轮廓存储在名为DetectedObject的类中:

class DetectedObject:
    def __init__(self, cnt):
        self.contour = cnt

    def draw(self, img):
        cv2.drawContours(img, self.contour, -1, (0, 255, 0), 3)

    # returns the top extrema of the contour
    def extrema(self):
        left = tuple(self.contour[self.contour[:, :, 0].argmin()][0])
        right = tuple(self.contour[self.contour[:, :, 0].argmax()][0])
        top = tuple(self.contour[self.contour[:, :, 1].argmin()][0])
        bottom = tuple(self.contour[self.contour[:, :, 1].argmax()][0])
        return (left, right, top, bottom)

问题是,当我像这样去迭代img.crop()时:

    img = FrontImage(cv2.imread(image), lh).crop(0)

    i = 0
    meta_cnts = []
    while i < img.size()[1]:
        # grab the contour data and append it to the metalist
        imgn = img.crop(i)
        print(cv2.moments(imgn.objs[0].contour))
        meta_cnts.append(imgn.objs[0].contour)
        i += 1

    np.save("contours", meta_cnts)

等高线的所有合成力矩均为零!这不会在其他类似方式的图像中再次出现,但是对于这个奇异的立方体,all时刻不存在了:

λ src/crunchwrap/model python main.py xyzCalibration_cube.obj                                  
'm00': 0.0, 'm10': 0.0, 'm01': 0.0, 'm20': 0.0, 'm11': 0.0, 'm02': 0.0, 'm30': 0.0, 'm21': 0.0, 'm12': 0.0, 'm03
': 0.0, 'mu20': 0.0, 'mu11': 0.0, 'mu02': 0.0, 'mu30': 0.0, 'mu21': 0.0, 'mu12': 0.0, 'mu03': 0.0, 'nu20': 0.0, '
nu11': 0.0, 'nu02': 0.0, 'nu30': 0.0, 'nu21': 0.0, 'nu12': 0.0, 'nu03': 0.0
(this continues for some time with the same output)

在Linux上运行OpenCV 4.2.0和Python 3.8.1。如果这个问题太冗长,我深表歉意。感谢您提供的所有帮助。

答案

我设法通过重构FrontImage来解决此问题,以避免每次仅在其初始运行时进行智能裁剪,例如:

    # gets the xy size of the image after smart-cropping
    def ext_size(self):
        x_size = self.extrema[0][0] - self.extrema[1][0]
        y_size = int(np.floor((self.extrema[3][1] - self.extrema[2][1]) / self.layer_height))
        return (x_size, y_size)

    # gets the xy size of the raw image
    def size(self):
        return (np.size(self.image, 1), np.size(self.image, 0))

    # crops the image based on extrema bounds and "height" to remove
    def smart_crop(self):
        # int(np.floor(()) converts it to a consistently "underapproximated" integer
        return FrontImage(self.image[self.extrema[2][1]:self.extrema[3][1], \
                                     self.extrema[1][0]:self.extrema[0][0]], self.layer_height)

    # crops but does not scale
    def crop(self, layers):
        return FrontImage(self.image[0:self.size()[1], 0:self.size()[0]], self.layer_height)

以上是关于轮廓的所有矩求零的主要内容,如果未能解决你的问题,请参考以下文章

opencvsharp_基于轮廓的形状匹配中匹配坐标与旋转角度

图像与轮廓检测-轮廓检测

从图像中删除所有轮廓

轮廓检测

AUTO CAD 实体生成轮廓命令

如何将灰度图像中的轮廓值设置为该轮廓的最大值?