我想根据图像的右边框裁剪图像.我有大约10000张手部X射线图像需要预处理,以及到目前为止我所做的工作:

  1. 在图像上应用高斯模糊和阈值(二进制+Otsu).
  2. 应用inflating 以获取单个对象(在本例中为手).
  3. 用于沿手周围的边缘绘制轮廓.
  4. 使用cv2.boundingRect()查找右帧,然后使用cv2.minAreaRect()cv2.boxPoints获得边界框的右点.
  5. 使用cv2.warpPerspective根据高度和宽度调整图像.

下面的代码描述了上述内容:

import os
import cv2
import numpy as np
from matplotlib import pyplot as plt

# Load image, create mask, grayscale, Gaussian blur, Otsu's threshold
img_path = "sample_image.png"

image = cv2.imread(image_path)
original = image.copy()
blank = np.zeros(image.shape[:2], dtype = np.uint8)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (33,33), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]

# Merge text into a single contour
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
dilate = cv2.dilate(thresh, kernel, iterations = 3)

# Find contours
cnts = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts = sorted(cnts, key = lambda x: cv2.boundingRect(x)[0])

for c in cnts:
    # Filter using contour area and aspect ratio (x1 = width, y1 = height)
    x, y, x1, y1 = cv2.boundingRect(c)
    if (x1 > 500) and (y1 > 700):
        rect = cv2.minAreaRect(c)
        box = cv2.boxPoints(rect)
        box = np.int0(box)
        width = int(rect[1][0])
        height = int(rect[1][1])
        src_pts = box.astype("float32")
        dst_pts = np.array([[0, height-1], [0, 0],
                            [width-1, 0], [width-1, height-1]], dtype="float32")

        M = cv2.getPerspectiveTransform(src_pts, dst_pts)
        warped = cv2.warpPerspective(image, M, (width, height))
        plt.imshow(warped)

如果你看some of the images in the folder,这些就是输入.当我通过上面的代码运行这些图像时,I get an output like this.其中一些修剪得很好(拉直),但是,其中一些是90度旋转修剪的.是否有代码来解决"旋转90度输出"问题?

以下是一些图片:

图像输入:Four X-ray examples

图像输出:Returns images that are 90 degrees rotated

需要图像输出:Straightened image(仅使用Photoshop将其拉直.不想对Straightened image00张图像执行此操作…)

更新:

我根据下面提到的建议编辑了代码.运行一些样本后,它现在返回向右倾斜90度的图像.

  • Input images: enter image description here

  • Output images: enter image description here

我怀疑这是因为图像的质量.也许这与OpenCV的minAreaRect()有关?还是boxPoints

FINAL 更新:

根据@Prashant Maurya的说法,代码被更新,增加了一个功能来检测手的位置是左还是右.然后将src\u pts映射到右侧dst\u pts.完整代码如下所示.

推荐答案

嗨,有两种改变可以纠正输出:

  • 代码中的宽度和高度顺序错误,即:宽度:1470&;高度:1118只需切换值:
  • 将src\u pts映射到右侧dst\u pts当前代码正在映射左上角
  • 增加了检测图像是向右倾斜还是向左倾斜的功能,并相应地旋转

更改后的完整代码为:

import os
import cv2
import numpy as np
from matplotlib import pyplot as plt

# Load image, create mask, grayscale, Gaussian blur, Otsu's threshold
img_path = "xray1.png"

image = cv2.imread(img_path)
cv2.imshow("image original", image)
cv2.waitKey(10000)
original = image.copy()
blank = np.zeros(image.shape[:2], dtype = np.uint8)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (33,33), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]

# Merge text into a single contour
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
dilate = cv2.dilate(thresh, kernel, iterations = 3)

# Find contours
cnts = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts = sorted(cnts, key = lambda x: cv2.boundingRect(x)[0])

def get_tilt(box):
    tilt = "Left"
    x_list = [coord[0] for coord in box]
    y_list = [coord[1] for coord in box]

    print(x_list)
    print(y_list)

    x_list = sorted(x_list)
    y_list = sorted(y_list)

    print(x_list)
    print(y_list)

    for coord in box:
        if coord[0] == x_list[0]:
            index = y_list.index(coord[1])
            print("Index: ", index)
            if index == 1:
                tilt = "Left"
            else:
                tilt = "Right"

    return tilt


for c in cnts:
    # Filter using contour area and aspect ratio (x1 = width, y1 = height)
    x, y, x1, y1 = cv2.boundingRect(c)
    if (x1 > 500) and (y1 > 700):
        rect = cv2.minAreaRect(c)
        print("rect",rect)
        box = cv2.boxPoints(rect)
        box = np.int0(box)
        # print("rect:", box)
        tilt = get_tilt(box)

        src_pts = box.astype("float32")

        if tilt == "Left":
            width = int(rect[1][1])
            height = int(rect[1][0])
            dst_pts = np.array([[0, 0],
                                [width-1, 0], [width-1, height-1], [0, height-1]], dtype="float32")
        else:
            width = int(rect[1][0])
            height = int(rect[1][1])
            dst_pts = np.array([[0, height-1], [0, 0],
                            [width-1, 0], [width-1, height-1]], dtype="float32")

        print("Src pts:", src_pts)
        print("Dst pts:", dst_pts)
        M = cv2.getPerspectiveTransform(src_pts, dst_pts)
        warped = cv2.warpPerspective(image, M, (width, height))
        print("Showing image ..")
        # plt.imshow(warped)
        cv2.imshow("image crop", warped)
        cv2.waitKey(10000)

Python相关问答推荐

为什么sys.exit()不能与subproccess.run()或subprocess.call()一起使用

Julia CSV for Python中的等效性Pandas index_col参数

用NumPy优化a[i] = a[i-1]*b[i] + c[i]的迭代计算

如何获得每个组的时间戳差异?

如何在Polars中从列表中的所有 struct 中 Select 字段?

删除marplotlib条形图上的底边

如何指定列数据类型

使用特定值作为引用替换数据框行上的值

如何在PySide/Qt QColumbnView中删除列

Pandas 数据帧中的枚举,不能在枚举列上执行GROUP BY吗?

如何在PythonPandas 中对同一个浮动列进行逐行划分?

Python协议不兼容警告

如果服务器设置为不侦听创建,则QWebSocket客户端不连接到QWebSocketServer;如果服务器稍后开始侦听,则不连接

类型对象';敌人';没有属性';损害';

如何获取给定列中包含特定值的行号?

如何从一个维基页面中抓取和存储多个表格?

无法使用请求模块从网页上抓取一些产品的名称

Pandas:使列中的列表大小与另一列中的列表大小相同

打印:添加具有不同填充 colored颜色 的矩形

有理由将基于Django职业的观点个人化吗?