Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/opencv/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 提取矩形的尺寸_Python_Opencv_Image Processing - Fatal编程技术网

Python 提取矩形的尺寸

Python 提取矩形的尺寸,python,opencv,image-processing,Python,Opencv,Image Processing,所以我在做一个声纳图像的图像处理项目。更具体地说,我试图提取声纳扫描仪拍摄的水池图像的尺寸。我能够提取池的矩形区域,但我不知道如何获得每个边的像素尺寸。我正在Python中使用OpenCV 如果有人能就如何做到这一点给我任何建议,我将不胜感激 我已经尝试过寻找hough线的线交点,但没有什么好结果 代码到目前为止 导入cv2 将numpy作为np导入 从scipy导入ndi图像作为ndi 从scipy.ndimage.measurements导入标签 def最大_组件(索引): #此函数获取一个

所以我在做一个声纳图像的图像处理项目。更具体地说,我试图提取声纳扫描仪拍摄的水池图像的尺寸。我能够提取池的矩形区域,但我不知道如何获得每个边的像素尺寸。我正在Python中使用OpenCV

如果有人能就如何做到这一点给我任何建议,我将不胜感激

我已经尝试过寻找hough线的线交点,但没有什么好结果

代码到目前为止

导入cv2
将numpy作为np导入
从scipy导入ndi图像作为ndi
从scipy.ndimage.measurements导入标签
def最大_组件(索引):
#此函数获取一个表示
#图像的白色区域,并返回最大值
#连通指数的白色对象
return\u arr=np.zeros((512512),dtype=np.uint8)
对于索引中的索引:
返回\u arr[索引[0]][索引[1]]=255
返回
image=cv2.imread('sonar\u dataset/usive/sonarXY\u 5.bmp',0)
图像\u高斯=ndi.高斯滤波器(图像,4)
image\u gaussian\u inv=cv2。按位\u not(image\u gaussian)
内核=np.ones((3,3),np.uint8)
#双阈值提取矩形的边
ret1,img1=cv2.阈值(图像\u高斯\u inv,120255,cv2.阈值\u二进制)
ret2,img2=cv2.阈值(图像\u高斯\u inv,150255,cv2.阈值\u二进制)
双阈值=img1-img2
关闭=cv2.morphologyEx(双阈值,cv2.Morpho\u关闭,内核1)
已标记,ncomponents=标签(关闭,内核)
index=np.index(closing.shape).T[:,:,[1,0]]
twos=索引[标记==2]
区域=[ncomponents+1]范围内的val的np.sum(标记==val)]
矩形=最大的_分量(两个)
cv2.imshow('矩形',矩形)
cv2.等待键(0)
原始图像和提取的对象如下所示


这并不完美,但这种简单的方法应该是您的良好起点:

import cv2, math
import numpy as np

img = cv2.imread(R'D:\dev\projects\stackoverflow\dimensions_of_rectangle\img1.png')
print(img.shape)
img_moments=cv2.moments(img[:,:,0]) #use only one channel here (cv2.moments operates only on single channels images)
print(img_moments)
# print(dir(img_moments))

# calculate centroid (center of mass of image)
x = img_moments['m10'] / img_moments['m00']
y = img_moments['m01'] / img_moments['m00']

# calculate orientation of image intensity (it corresponds to the image intensity axis)
u00 = img_moments['m00']
u20 = img_moments['m20'] - x*img_moments['m10']
u02 = img_moments['m02'] - y*img_moments['m01']
u11 = img_moments['m11'] - x*img_moments['m01']

u20_prim = u20/u00
u02_prim = u02/u00
u11_prim = u11/u00

angle = 0.5 * math.atan(2*u11_prim / (u20_prim - u02_prim))
print('The image should be rotated by: ', math.degrees(angle) / 2.0, ' degrees')

cols,rows = img.shape[:2]
# rotate the image by half of this angle
rotation_matrix = cv2.getRotationMatrix2D((cols/2,rows/2), math.degrees(angle / 2.0), 1)
img_rotated = cv2.warpAffine(img, rotation_matrix ,(cols,rows))
# print(img_rotated.shape, img_rotated.dtype)

cv2.imwrite(R'D:\dev\projects\stackoverflow\dimensions_of_rectangle\img1_rotated.png', img_rotated)

img_rotated_clone = np.copy(img_rotated)
img_rotated_clone2 = np.copy(img_rotated)

# first method - just calculate bounding rect
bounding_rect = cv2.boundingRect(img_rotated[:, :, 0])
cv2.rectangle(img_rotated_clone, (bounding_rect[0], bounding_rect[1]), 
    (bounding_rect[0] + bounding_rect[2], bounding_rect[1] + bounding_rect[3]), (255,0,0), 2)

# second method - find columns and rows with biggest sums
def nlargest_cols(a, n):
    col_sums = [(np.sum(col), idx) for idx, col in enumerate(a.T)]
    return sorted(col_sums, key=lambda a: a[0])[-n:]

def nlargest_rows(a, n):
    col_sums = [(np.sum(col), idx) for idx, col in enumerate(a[:,])]
    return sorted(col_sums, key=lambda a: a[0])[-n:]

top15_cols_indices = nlargest_cols(img_rotated[:,:,0], 15)
top15_rows_indices = nlargest_rows(img_rotated[:,:,0], 15)

for a in top15_cols_indices:
    cv2.line(img_rotated_clone, (a[1], 0), (a[1], rows), (0, 255, 0), 1)

for a in top15_rows_indices:
    cv2.line(img_rotated_clone, (0, a[1]), (cols, a[1]), (0, 0, 255), 1)

cv2.imwrite(R'D:\dev\projects\stackoverflow\dimensions_of_rectangle\img2.png', img_rotated_clone)
当然,您需要调整路径。img1.png是您问题中的第二幅图像,img1_旋转是旋转图像的结果:

img2是最终输出:

蓝色矩形是method1(只是一个边界矩形),绿色和红色线条(15条红色和15条绿色-所有1个像素宽)是第二种方法

算法非常简单:

  • 计算图像力矩以确定图像强度的主轴(我不知道如何描述它-查看wiki页面)。基本上,这是一个角度,您必须旋转图像以使白色像素水平或垂直分布
  • 知道角度后,旋转图像(并保存结果)
  • 方法1-计算并绘制所有像素的旋转矩形
  • 方法2-找到15行和15列的最大和(=白色像素的最大计数),并在这些行/列中绘制水平/垂直线。请注意,数字15是通过反复试验选择的,但应该很容易选择两列(和两行)的总和较大且彼此不接近。这些列/行很适合作为矩形边界

  • 希望这就是你想要的,让我知道你会有任何问题。

    所以我想到了一个办法——这有点耗费人力,但最终我们还是找到了正确的答案。我将直接使用您在最后一张图像中显示的连接组件输出

  • 使用,以便我们获得水滴的骨架。这样,它将为我们提供最简单的轮廓表示,这样我们可以得到一个像素宽的边界,通过每个厚边的中间。您可以通过Scikit image的方法实现这一点

  • 使用骨骼化图像上的线条检测方法。总之,它将极域中的线参数化,输出将是一组
    rho
    theta
    ,告诉我们在骨架化图像中检测到哪些线。我们可以使用OpenCV来实现这一点。在骨架化图像上执行此操作非常重要,否则我们将有许多候选线与边界框的真实轮廓平行,您将无法区分它们

  • 取每对线,找出它们的交点。我们预计,对于所有的线对,将有4个主要的交叉点簇,它们为我们提供每个矩形的角

  • from skimage.morphology import skeletonize
    import cv2
    import numpy as np
    
    # Step #1 - Skeletonize
    im = cv2.imread('K7ELI.png', 0)
    out = skeletonize(im > 0)
    
    # Convert to uint8
    out = 255*(out.astype(np.uint8))
    
    # Step #2 - Hough Transform
    lines = cv2.HoughLines(out,1,np.pi/180,60)
    
    # Step #3 - Find points of intersection
    pts = []
    for i in range(lines.shape[0]):
        (rho1, theta1) = lines[i,0]
        m1 = -1/np.tan(theta1)
        c1 = rho1 / np.sin(theta1)
        for j in range(i+1,lines.shape[0]):
            (rho2, theta2) = lines[j,0]
            m2 = -1 / np.tan(theta2)
            c2 = rho2 / np.sin(theta2)
            if np.abs(m1 - m2) <= 1e-8:
                continue
            x = (c2 - c1) / (m1 - m2)
            y = m1*x + c1
            if 0 <= x < img.shape[1] and 0 <= y < img.shape[0]:
                pts.append((int(x), int(y)))
    
    # Step #4 - Find convex hull
    pts = np.array(pts)
    pts = pts[:,None] # We need to convert to a 3D numpy array with a singleton 2nd dimension
    hull = cv2.convexHull(pts)
    
    # Step #5 - K-Means clustering
    # Define criteria = ( type, max_iter = 10 , epsilon = 1.0 )
    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
    
    # Set flags (Just to avoid line break in the code)
    flags = cv2.KMEANS_RANDOM_CENTERS
    
    # Apply KMeans
    # The convex hull points need to be float32
    z = hull.copy().astype(np.float32)
    compactness,labels,centers = cv2.kmeans(z,4,None,criteria,10,flags)
    
    # Step #6 - Find the lengths of each side
    centers = cv2.convexHull(centers)[:,0]
    for (i, j) in zip(range(4), [1, 2, 3, 0]):
        length = np.sqrt(np.sum((centers[i] - centers[j])**2.0))
        print('Length of side {}: {}'.format(i+1, length))
    
    # Draw the sides of each rectangle in the original image
    out5 = cv2.imread('no8BP.png') # Note - grayscale image read in as colour
    for (i, j) in zip(range(4), [1, 2, 3, 0]):
        cv2.line(out5, tuple(centers[i]), tuple(centers[j]), (0, 0, 255), 2)
    
    # Show the image
    cv2.imshow('Output', out5); cv2.waitKey(0); cv2.destroyAllWindows()
    
  • 由于轮廓中的噪声,我们可能会得到四个以上的交点。我们可以使用最终得到矩形的4个交点。总之,凸包算法在点列表上运行,它定义了可以最小地包含点列表的点子集。我们可以使用

  • 最后,由于霍夫变换的量化,在每个角点附近可能有多个点。因此,应用以查找4个点簇,从而找到它们的质心。我们可以用它

  • 一旦我们找到质心,我们可以简单地循环遍历每对点,最终找到到每个角点的距离,从而找到您关心的距离

  • 让我们一个接一个地介绍每一点:

    步骤#1-形态图像骨架化 使用Scikit image的
    骨架化
    ,我们可以对上面显示的连接组件图像进行骨架化。请注意,在继续之前,需要将图像转换为二进制。调用该方法后,我们需要在余下的过程中转换回无符号8位整数。我已经下载了上面的图片并保存在本地。我们可以在以下情况下运行
    skeletonize
    方法:

    from skimage.morphology import skeletonize
    
    im = cv2.imread('K7ELI.png', 0)
    out = skeletonize(im > 0)
    
    # Convert to uint8
    out = 255*(out.astype(np.uint8))
    
    我们得到这样的图像:

    lines = cv2.HoughLines(out,1,np.pi/180,60)
    
    out3 = np.dstack([im, im, im])
    for pt in centers:
        cv2.circle(out3, tuple(pt), 2, (0, 255, 0), 2)
    

    步骤2-使用Hough变换 使用Hough变换,我们可以检测此图像中最突出的线条:

    lines = cv2.HoughLines(out,1,np.pi/180,60)
    
    out3 = np.dstack([im, im, im])
    for pt in centers:
        cv2.circle(out3, tuple(pt), 2, (0, 255, 0), 2)
    
    out2 = np.dstack([im, im, im])
    for pt in hull[:,0]:
        cv2.circle(out2, tuple(pt), 2, (0, 255, 0), 2)
    
    # Define criteria = ( type, max_iter = 10 , epsilon = 1.0 )
    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
    
    # Set flags (Just to avoid line break in the code)
    flags = cv2.KMEANS_RANDOM_CENTERS
    
    # Apply KMeans
    # The convex hull points need to be float32
    z = hull.copy().astype(np.float32)
    compactness,labels,centers = cv2.kmeans(z,4,None,criteria,10,flags)
    
    array([[338.5   , 152.5   ],
           [302.6667, 368.6667],
           [139.    , 340.    ],
           [178.5   , 127.    ]], dtype=float32)
    
    out3 = np.dstack([im, im, im])
    for pt in centers:
        cv2.circle(out3, tuple(pt), 2, (0, 255, 0), 2)
    
    centers = cv2.convexHull(centers)[:,0]
    for (i, j) in zip(range(4), [1, 2, 3, 0]):
        length = np.sqrt(np.sum((centers[i] - centers[j])**2.0))
        print('Length of side {}: {}'.format(i+1, length))
    
    Length of side 1: 219.11654663085938
    Length of side 2: 166.1582489013672
    Length of side 3: 216.63160705566406
    Length of side 4: 162.019287109375
    
    out4 = np.dstack([im, im, im])
    for (i, j) in zip(range(4), [1, 2, 3, 0]):
        cv2.line(out4, tuple(centers[i]), tuple(centers[j]), (0, 0, 255), 2)
    
    out5 = cv2.imread('no8BP.png') # Note - grayscale image read in as colour
    for (i, j) in zip(range(4), [1, 2, 3, 0]):
        cv2.line(out5, tuple(centers[i]), tuple(centers[j]), (0, 0, 255), 2)
    
    from skimage.morphology import skeletonize
    import cv2
    import numpy as np
    
    # Step #1 - Skeletonize
    im = cv2.imread('K7ELI.png', 0)
    out = skeletonize(im > 0)
    
    # Convert to uint8
    out = 255*(out.astype(np.uint8))
    
    # Step #2 - Hough Transform
    lines = cv2.HoughLines(out,1,np.pi/180,60)
    
    # Step #3 - Find points of intersection
    pts = []
    for i in range(lines.shape[0]):
        (rho1, theta1) = lines[i,0]
        m1 = -1/np.tan(theta1)
        c1 = rho1 / np.sin(theta1)
        for j in range(i+1,lines.shape[0]):
            (rho2, theta2) = lines[j,0]
            m2 = -1 / np.tan(theta2)
            c2 = rho2 / np.sin(theta2)
            if np.abs(m1 - m2) <= 1e-8:
                continue
            x = (c2 - c1) / (m1 - m2)
            y = m1*x + c1
            if 0 <= x < img.shape[1] and 0 <= y < img.shape[0]:
                pts.append((int(x), int(y)))
    
    # Step #4 - Find convex hull
    pts = np.array(pts)
    pts = pts[:,None] # We need to convert to a 3D numpy array with a singleton 2nd dimension
    hull = cv2.convexHull(pts)
    
    # Step #5 - K-Means clustering
    # Define criteria = ( type, max_iter = 10 , epsilon = 1.0 )
    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
    
    # Set flags (Just to avoid line break in the code)
    flags = cv2.KMEANS_RANDOM_CENTERS
    
    # Apply KMeans
    # The convex hull points need to be float32
    z = hull.copy().astype(np.float32)
    compactness,labels,centers = cv2.kmeans(z,4,None,criteria,10,flags)
    
    # Step #6 - Find the lengths of each side
    centers = cv2.convexHull(centers)[:,0]
    for (i, j) in zip(range(4), [1, 2, 3, 0]):
        length = np.sqrt(np.sum((centers[i] - centers[j])**2.0))
        print('Length of side {}: {}'.format(i+1, length))
    
    # Draw the sides of each rectangle in the original image
    out5 = cv2.imread('no8BP.png') # Note - grayscale image read in as colour
    for (i, j) in zip(range(4), [1, 2, 3, 0]):
        cv2.line(out5, tuple(centers[i]), tuple(centers[j]), (0, 0, 255), 2)
    
    # Show the image
    cv2.imshow('Output', out5); cv2.waitKey(0); cv2.destroyAllWindows()