1
我想要的x射線圖像中的下面(通過使用Python):對齊的X射線圖像:找到旋轉,旋轉和裁剪
- 識別(不完善)矩形塊的旋轉
- 旋轉圖像,使其垂直(縱向形式)
- 刪除通過裁剪剩餘的空白
我想這部分的this question相反,其中工具最有可能與另外的相同一個corner detector。我不完全確定如何最好地解決這個問題,而且這似乎是某個人已經解決的問題。
我想要的x射線圖像中的下面(通過使用Python):對齊的X射線圖像:找到旋轉,旋轉和裁剪
我想這部分的this question相反,其中工具最有可能與另外的相同一個corner detector。我不完全確定如何最好地解決這個問題,而且這似乎是某個人已經解決的問題。
這可以使用Python綁定到OpenCV
庫來完成。下面的代碼已經從我以前的東西改編而來,所以它可能會進一步優化和改進。
您給出的圖像不僅是旋轉的,它也不是矩形的,因爲這樣的腳本在兩個主要階段中起作用。首先它確定圖像上的旋轉並旋轉並在最小矩形周圍進行裁剪。然後拉伸產生的圖像以適應所得到的矩形。
初始閾值圖像
初始邊界矩形
旋轉並且裁剪圖像
多邊形舒展從
最終裁剪圖像
import numpy as np
import cv2
import math
THRESHOLD = 240
def subimage(image, center, theta, width, height):
if 45 < theta <= 90:
theta = theta - 90
width, height = height, width
theta *= math.pi/180 # convert to rad
v_x = (math.cos(theta), math.sin(theta))
v_y = (-math.sin(theta), math.cos(theta))
s_x = center[0] - v_x[0] * (width/2) - v_y[0] * (height/2)
s_y = center[1] - v_x[1] * (width/2) - v_y[1] * (height/2)
mapping = np.array([[v_x[0],v_y[0], s_x], [v_x[1],v_y[1], s_y]])
return cv2.warpAffine(image, mapping, (width, height), flags=cv2.WARP_INVERSE_MAP, borderMode=cv2.BORDER_REPLICATE)
def auto_crop(image_source):
# First slightly crop edge - some images had a rogue 2 pixel black edge on one side
init_crop = 5
h, w = image_source.shape[:2]
image_source = image_source[init_crop:init_crop+(h-init_crop*2), init_crop:init_crop+(w-init_crop*2)]
# Add back a white border
image_source = cv2.copyMakeBorder(image_source, 5,5,5,5, cv2.BORDER_CONSTANT, value=(255,255,255))
image_gray = cv2.cvtColor(image_source, cv2.COLOR_BGR2GRAY)
_, image_thresh = cv2.threshold(image_gray, THRESHOLD, 255, cv2.THRESH_BINARY)
image_thresh2 = image_thresh.copy()
image_thresh2 = cv2.Canny(image_thresh2, 100, 100, apertureSize=3)
points = cv2.findNonZero(image_thresh2)
centre, dimensions, theta = cv2.minAreaRect(points)
rect = cv2.minAreaRect(points)
width = int(dimensions[0])
height = int(dimensions[1])
box = cv2.boxPoints(rect)
box = np.int0(box)
temp = image_source.copy()
cv2.drawContours(temp, [box], 0, (255,0,0), 2)
M = cv2.moments(box)
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
image_patch = subimage(image_source, (cx, cy), theta+90, height, width)
# add back a small border
image_patch = cv2.copyMakeBorder(image_patch, 1,1,1,1, cv2.BORDER_CONSTANT, value=(255,255,255))
# Convert image to binary, edge is black. Do edge detection and convert edges to a list of points.
# Then calculate a minimum set of points that can enclose the points.
_, image_thresh = cv2.threshold(image_patch, THRESHOLD, 255, 1)
image_thresh = cv2.Canny(image_thresh, 100, 100, 3)
points = cv2.findNonZero(image_thresh)
hull = cv2.convexHull(points)
# Find min epsilon resulting in exactly 4 points, typically between 7 and 21
# This is the smallest set of 4 points to enclose the image.
for epsilon in range(3, 50):
hull_simple = cv2.approxPolyDP(hull, epsilon, 1)
if len(hull_simple) == 4:
break
hull = hull_simple
# Find closest fitting image size and warp/crop to fit
# (ie reduce scaling to a minimum)
x,y,w,h = cv2.boundingRect(hull)
target_corners = np.array([[0,0],[w,0],[w,h],[0,h]], np.float32)
# Sort hull into tl,tr,br,bl order.
# n.b. hull is already sorted in clockwise order, we just need to know where top left is.
source_corners = hull.reshape(-1,2).astype('float32')
min_dist = 100000
index = 0
for n in xrange(len(source_corners)):
x,y = source_corners[n]
dist = math.hypot(x,y)
if dist < min_dist:
index = n
min_dist = dist
# Rotate the array so tl is first
source_corners = np.roll(source_corners , -(2*index))
try:
transform = cv2.getPerspectiveTransform(source_corners, target_corners)
return cv2.warpPerspective(image_patch, transform, (w,h))
except:
print "Warp failure"
return image_patch
cv2.namedWindow("Result")
image_src = cv2.imread("xray.png")
image_cropped = auto_crop(image_src)
cv2.imwrite("cropped xray.png", image_cropped)
cv2.imshow("Result", image_cropped)
cv2.waitKey(0)
由於去這個StackOverflow answer爲subimage
功能。
測試Python 2.7和OpenCV 3.0
謝謝!一直試圖在一組不同的圖像集,我想能夠使用uint8的numpy矩陣作爲輸入,但我還沒有完全想到如何以最好的方式做到這一點。其次,我在零(int [M ['m10']/M ['m00'])'(應該很容易修復),斷言錯誤「src.checkVector(2,CV_32F)== 4 && dst.checkVector(2,CV_32F)== 4「at'transform = cv2.getPerspectiveTransform(source_corners,target_corners)',和一個神祕的」(-215)total> = 0 &&(depth == CV_32F || depth == CV_32S )「線上的錯誤'hull = cv2.convexHull(points)'。有任何想法嗎? –
是的,它確實需要測試一系列文件。我的其他代碼遇到了'findContours'返回許多輪廓的問題。我覺得隨着你的進行,最容易顯示圖像。也可以使用drawContours來查看它認爲邊緣的位置。不確定在uint8上,需要調查。 –
我做了一些改變。它不再使用findContours。我還發現,如果在拉伸之前添加白色邊框,效果會更好。這對我自己的測試圖像效果更好。 –