Мне нужно разделить или обрезать изображение в несколько ящиков, отображаемых на изображении. Ниже приведен мой код, который может разбивать изображение, но я не могу создать 15 разных ящиков, используя свой код.
Мой код приведен ниже:
import math, cv2
from scipy import misc
import numpy
def getFactors(num):
"""
Split the input number into factors nearest to its square root. May not be
the most efficient for large numbers, but will do for numbers smaller than 1000.
"""
sqt = int(math.sqrt(num))
if (num % sqt) == 0:
return (sqt,int(num/sqt))
num1 = sqt
num2 = sqt
while True:
num1 += 1
num2 -= 1
if (num1 >= num) or (num2 <= 0):
return (num, 1)
if (num % num1) == 0:
return (num1, int(num/num1))
if (num % num2) == 0:
return (num2, int(num/num2))
return
def splitImage(img, numsplits):
"""
Split the input image into number of splits provided by the second argument.
The results are stored in a numpy array res and returned. The last index of the
res array indexes the individual parts.
"""
# Get the factors for splitting. So if the number of splits is 9, then (3,3)
# or if 6 then (2,3) etc.
factors = getFactors(numsplits)
# Height and width of each split
h = int(img.shape[0] / factors[0])
w = int(img.shape[1] / factors[1])
# Handle both color and B&W images
if img.ndim >= 3:
size = (h,w,img.shape[2],numsplits)
else:
size = (h,w,numsplits)
# Initialize the result array
res = numpy.ndarray( size, dtype = img.dtype )
# Iterate through the number of factors to split the source image horizontally
# and vertically, and store the resultant chunks
for i in range(factors[0]):
for j in range(factors[1]):
if img.ndim >= 3:
res[:,:,:,((i*factors[1])+j)] = img[(i*h):((i+1)*h), (j*w):((j+1)*w),:]
else:
res[:,:,((i*factors[1])+j)] = img[(i*h):((i+1)*h), (j*w):((j+1)*w)]
return res
def cropImage(img):
"""
Detect lines in the image to crop it so that the resultant image can be split well.
We use here Canny edge detection followed by Hough Line Transform.
"""
# Convert image to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Detect edges and lines
edges = cv2.Canny(gray, 50, 150, apertureSize = 3)
lines = cv2.HoughLines(edges, 1, numpy.pi/90, 200)
min_x = img.shape[0]
max_x = 0
min_y = img.shape[1]
max_y = 0
# Find the extremal horizontal and vertical coordinates to crop
for i in range(len(lines[:,0,0])):
rho = lines[i,0,0]
theta = lines[i,0,1]
a = numpy.cos(theta)
b = numpy.sin(theta)
x = a*rho
y = b*rho
if abs(a) < 1e-06 :
if min_y > int(y):
min_y = int(y)
if max_y < int(y):
max_y = int(y)
if abs(b) < 1e-06 :
if min_x > int(x):
min_x = int(x)
if max_x < int(x):
max_x = int(x)
return img[min_y:max_y, min_x:max_x, :]
# Read image
img = misc.imread('tmp.png')
# Crop the image
img = cropImage(img)
# Call the splitter function
res = splitImage(img, 6)
# Save the results to files
for i in range(res.shape[-1]):
if img.ndim >= 3:
misc.imsave('res_{0:03d}.png'.format(i),res[:,:,:,i])
else:
misc.imsave('res_{0:03d}.png'.format(i),res[:,:,i])
Теперь я хочу обрезать или разделить его на 15 различных ящиков, доступных на прилагаемом изображении. Я не могу найти решение.
Легким решением может быть использование встроенной функции из OpenCV findContours
Он найдет все контуры, присутствующие в вашем изображении (возвращается как список контуров), в вашем примере есть большие шансы, что он обнаружит ваши поля.
Затем вы можете перебирать этот список, чтобы получить ограничивающие прямоугольники вашего контура. Оттуда вы можете создавать свои вспомогательные изображения, нарезая исходные изображения с помощью координат рамки.
_, contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for contour in countours:
(_x, _y, w, h) = cv2.boundingRect(contour)
Официальный учебник по использованию cv2.findContours:
https://docs.opencv.org/3.3.1/d4/d73/tutorial_py_contours_begin.html