IndexError: index 3 is out of bounds for axis 0 with size 3 while giving original image (color image)?
IndexError: index 3 is out of bounds for axis 0 with size 3 while giving original image (color image)?
我正在尝试使用 open cv 应用透视信息来取消剪切图像。我已将图像转换为黑白图像,然后将其传递给工作正常的模型。它正在显示实际上是输出的白色遮罩。我如何显示其原始图像对象而不是 mask ,它抛出索引错误。
**代码:**
import cv2
import numpy as np
def find_corners(im):
# Find contours in img.
cnts = cv2.findContours(im, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2] # [-2] indexing takes return value before last (due to OpenCV compatibility issues).
# Find the contour with the maximum area (required if there is more than one contour).
c = max(cnts, key=cv2.contourArea)
epsilon = 0.1*cv2.arcLength(c, True)
box = cv2.approxPolyDP(c, epsilon, True)
tmp_im = cv2.cvtColor(im, cv2.COLOR_GRAY2BGR)
cv2.drawContours(tmp_im, [box], 0, (0, 255, 0), 2)
cv2.imshow("tmp_im", tmp_im)
box = np.squeeze(box).astype(np.float32)
# Sorting the points order is top-left, top-right, bottom-right, bottom-left.
# Find the center of the contour
M = cv2.moments(c)
cx = M['m10']/M['m00']
cy = M['m01']/M['m00']
center_xy = np.array([cx, cy])
cbox = box - center_xy # Subtract the center from each corner
ang = np.arctan2(cbox[:,1], cbox[:,0]) * 180 / np.pi # Compute the angles from the center to each corner
# Sort the corners of box counterclockwise (sort box elements according the order of ang).
box = box[ang.argsort()]
# Reorder points: top-left, top-right, bottom-left, bottom-right
print('bbox',box)
coor = np.float32([box[0], box[1], box[3], box[2]])
return coor
input_image2 = cv2.imread("/home/hamza/Desktop/cards/card2.jpeg", cv2.IMREAD_GRAYSCALE) # Read image as Grayscale
input_image2 = cv2.threshold(input_image2, 0, 255, cv2.THRESH_OTSU)[1] # Convert to binary image (just in case...)
# Find the corners of the card, and sort them
orig_im_coor = find_corners(input_image2)
height, width = 450, 350
new_image_coor = np.float32([[0, 0], [width, 0], [0, height], [width, height]])
P = cv2.getPerspectiveTransform(orig_im_coor, new_image_coor)
perspective = cv2.warpPerspective(input_image2, P, (width, height))
cv2.imshow("Perspective transformation", perspective)
cv2.waitKey(0)
cv2.destroyAllWindows()
原图
黑白图像
预期输出:
我得到的输出是来自代码的白色蒙版,这很好,但我想拍摄那个特定蒙版的图像。我怎样才能访问它?
如果无法使用这种方法,我该如何通过其他方法来实现?
编辑 1:
代码在取消剪切图像后返回输出,如下图所示,我必须将该特定蒙版放在该输出图像上,我将其作为指定图像的蒙版输入
代码现在返回输出。下面的输出图像是白色的,请按下它会显示你的图像,否则背景也是白色的,它不会正确显示你:
您需要做的就是对原始图像而不是黑白图像应用变换 cv2.warpPerspective
。
- 阅读“原图”:
original_image = cv2.imread("original_image.jpg")
- 像以前一样计算
orig_im_coor
和 P
。
- 在
original_image
上应用转换:
perspective = cv2.warpPerspective(original_image, P, (width, height))
还有一个推荐阶段:
与其手动设置高度和宽度:height, width = 450, 350
,建议计算高度和宽度。
假设orig_im_coor
坐标足够准确,我们可以根据坐标计算height
、width
:
- 宽度大约是从左上角到右上角的距离。
- 高度大约是从左上角到左下角的距离。
计算欧氏距离很简单:sqrt(x2 + y2).
作为快捷方式,我们可以使用 np.linalg.norm(a-b)
,如下所述 post:
width = round(np.linalg.norm(orig_im_coor[0] - orig_im_coor[1])) # Assume width is the distance from top-left to top-right
height = round(np.linalg.norm(orig_im_coor[0] - orig_im_coor[2])) # Assume height is the distance from top-left to bottom-left
完整代码如下:
import cv2
import numpy as np
def find_corners(im):
"""
Find "card" corners in a binary image.
Return a list of points in the following format: [[640, 184], [1002, 409], [211, 625], [589, 940]]
The points order is top-left, top-right, bottom-left, bottom-right.
"""
# Better approach:
# Find contours in img.
cnts = cv2.findContours(im, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2] # [-2] indexing takes return value before last (due to OpenCV compatibility issues).
# Find the contour with the maximum area (required if there is more than one contour).
c = max(cnts, key=cv2.contourArea)
#
epsilon = 0.1*cv2.arcLength(c, True)
box = cv2.approxPolyDP(c, epsilon, True)
# Draw box for testing
#tmp_im = cv2.cvtColor(im, cv2.COLOR_GRAY2BGR)
#cv2.drawContours(tmp_im, [box], 0, (0, 255, 0), 2)
#cv2.imshow("tmp_im", tmp_im)
box = np.squeeze(box).astype(np.float32) # Remove redundant dimensions
# Sorting the points order is top-left, top-right, bottom-right, bottom-left.
# Note:
# The method I am using is a bit of an "overkill".
# I am not sure if the implementation is correct.
# You may sort the corners using simple logic - find top left, bottom right, and match the other two points.
############################################################################
# Find the center of the contour
# https://docs.opencv.org/3.4/dd/d49/tutorial_py_contour_features.html
M = cv2.moments(c)
cx = M['m10']/M['m00']
cy = M['m01']/M['m00']
center_xy = np.array([cx, cy])
cbox = box - center_xy # Subtract the center from each corner
# For a square the angles of the corners are:
# -135 -45
#
#
# 135 45
ang = np.arctan2(cbox[:,1], cbox[:,0]) * 180 / np.pi # Compute the angles from the center to each corner
# Sort the corners of box counterclockwise (sort box elements according the order of ang).
box = box[ang.argsort()]
############################################################################
# Reorder points: top-left, top-right, bottom-left, bottom-right
coor = np.float32([box[0], box[1], box[3], box[2]])
return coor
original_image = cv2.imread("original_image.jpg") # Read the original image
bw_mask = cv2.imread("black_and_white_mask.jpg", cv2.IMREAD_GRAYSCALE) # Read image as Grayscale
bw_mask = cv2.threshold(bw_mask, 0, 255, cv2.THRESH_OTSU)[1] # Convert to binary image (just in case...)
# Find the corners of the mask, and sort them
orig_im_coor = find_corners(bw_mask)
# Compute width and height of the destination image according to orig_im_coor
#
width = round(np.linalg.norm(orig_im_coor[0] - orig_im_coor[1])) # Assume width is the distance from top-left to top-right
height = round(np.linalg.norm(orig_im_coor[0] - orig_im_coor[2])) # Assume height is the distance from top-left to bottom-left
#height, width = 450, 350
new_image_coor = np.float32([[0, 0], [width, 0], [0, height], [width, height]])
P = cv2.getPerspectiveTransform(orig_im_coor, new_image_coor)
#perspective = cv2.warpPerspective(input_image2, P, (width, height))
# Apply the perspective transform on the original_image
perspective = cv2.warpPerspective(original_image, P, (width, height))
cv2.imshow("Perspective transformation", perspective)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果:
更新:
在不变形的情况下裁剪遮罩区域。
这里是一个不变形裁剪的例子:
original_image = cv2.imread("original_image.jpg") # Read the original image
bw_mask = cv2.imread("black_and_white_mask.jpg", cv2.IMREAD_GRAYSCALE) # Read image as Grayscale
bw_mask = cv2.threshold(bw_mask, 0, 255, cv2.THRESH_OTSU)[1] # Convert to binary image (just in case...)
# Find the corners of the mask, and sort them
orig_im_coor = find_corners(bw_mask)
# Mask the background - place zeros where mask is zero
masked_image = cv2.bitwise_and(original_image, original_image, mask=bw_mask)
# The corners are the minimum and maximum of orig_im_coor
x0 = int(round(orig_im_coor[:, 0].min()))
y0 = int(round(orig_im_coor[:, 1].min()))
x1 = int(round(orig_im_coor[:, 0].max()))
y1 = int(round(orig_im_coor[:, 1].max()))
cropped_masked_image = masked_image[y0:y1+1, x0:x1+1, :].copy() # Crop area from top-left to bottom-right
# Show the results:
cv2.imshow('masked_image', masked_image)
cv2.imshow('cropped_masked_image', cropped_masked_image)
cv2.waitKey()
cv2.destroyAllWindows()
结果:
masked_image
:
cropped_masked_image
:
我正在尝试使用 open cv 应用透视信息来取消剪切图像。我已将图像转换为黑白图像,然后将其传递给工作正常的模型。它正在显示实际上是输出的白色遮罩。我如何显示其原始图像对象而不是 mask ,它抛出索引错误。
**代码:**
import cv2
import numpy as np
def find_corners(im):
# Find contours in img.
cnts = cv2.findContours(im, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2] # [-2] indexing takes return value before last (due to OpenCV compatibility issues).
# Find the contour with the maximum area (required if there is more than one contour).
c = max(cnts, key=cv2.contourArea)
epsilon = 0.1*cv2.arcLength(c, True)
box = cv2.approxPolyDP(c, epsilon, True)
tmp_im = cv2.cvtColor(im, cv2.COLOR_GRAY2BGR)
cv2.drawContours(tmp_im, [box], 0, (0, 255, 0), 2)
cv2.imshow("tmp_im", tmp_im)
box = np.squeeze(box).astype(np.float32)
# Sorting the points order is top-left, top-right, bottom-right, bottom-left.
# Find the center of the contour
M = cv2.moments(c)
cx = M['m10']/M['m00']
cy = M['m01']/M['m00']
center_xy = np.array([cx, cy])
cbox = box - center_xy # Subtract the center from each corner
ang = np.arctan2(cbox[:,1], cbox[:,0]) * 180 / np.pi # Compute the angles from the center to each corner
# Sort the corners of box counterclockwise (sort box elements according the order of ang).
box = box[ang.argsort()]
# Reorder points: top-left, top-right, bottom-left, bottom-right
print('bbox',box)
coor = np.float32([box[0], box[1], box[3], box[2]])
return coor
input_image2 = cv2.imread("/home/hamza/Desktop/cards/card2.jpeg", cv2.IMREAD_GRAYSCALE) # Read image as Grayscale
input_image2 = cv2.threshold(input_image2, 0, 255, cv2.THRESH_OTSU)[1] # Convert to binary image (just in case...)
# Find the corners of the card, and sort them
orig_im_coor = find_corners(input_image2)
height, width = 450, 350
new_image_coor = np.float32([[0, 0], [width, 0], [0, height], [width, height]])
P = cv2.getPerspectiveTransform(orig_im_coor, new_image_coor)
perspective = cv2.warpPerspective(input_image2, P, (width, height))
cv2.imshow("Perspective transformation", perspective)
cv2.waitKey(0)
cv2.destroyAllWindows()
原图
黑白图像
预期输出: 我得到的输出是来自代码的白色蒙版,这很好,但我想拍摄那个特定蒙版的图像。我怎样才能访问它?
如果无法使用这种方法,我该如何通过其他方法来实现?
编辑 1: 代码在取消剪切图像后返回输出,如下图所示,我必须将该特定蒙版放在该输出图像上,我将其作为指定图像的蒙版输入
代码现在返回输出。下面的输出图像是白色的,请按下它会显示你的图像,否则背景也是白色的,它不会正确显示你:
您需要做的就是对原始图像而不是黑白图像应用变换 cv2.warpPerspective
。
- 阅读“原图”:
original_image = cv2.imread("original_image.jpg")
- 像以前一样计算
orig_im_coor
和P
。 - 在
original_image
上应用转换:
perspective = cv2.warpPerspective(original_image, P, (width, height))
还有一个推荐阶段:
与其手动设置高度和宽度:height, width = 450, 350
,建议计算高度和宽度。
假设orig_im_coor
坐标足够准确,我们可以根据坐标计算height
、width
:
- 宽度大约是从左上角到右上角的距离。
- 高度大约是从左上角到左下角的距离。
计算欧氏距离很简单:sqrt(x2 + y2).
作为快捷方式,我们可以使用 np.linalg.norm(a-b)
,如下所述 post:
width = round(np.linalg.norm(orig_im_coor[0] - orig_im_coor[1])) # Assume width is the distance from top-left to top-right
height = round(np.linalg.norm(orig_im_coor[0] - orig_im_coor[2])) # Assume height is the distance from top-left to bottom-left
完整代码如下:
import cv2
import numpy as np
def find_corners(im):
"""
Find "card" corners in a binary image.
Return a list of points in the following format: [[640, 184], [1002, 409], [211, 625], [589, 940]]
The points order is top-left, top-right, bottom-left, bottom-right.
"""
# Better approach:
# Find contours in img.
cnts = cv2.findContours(im, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2] # [-2] indexing takes return value before last (due to OpenCV compatibility issues).
# Find the contour with the maximum area (required if there is more than one contour).
c = max(cnts, key=cv2.contourArea)
#
epsilon = 0.1*cv2.arcLength(c, True)
box = cv2.approxPolyDP(c, epsilon, True)
# Draw box for testing
#tmp_im = cv2.cvtColor(im, cv2.COLOR_GRAY2BGR)
#cv2.drawContours(tmp_im, [box], 0, (0, 255, 0), 2)
#cv2.imshow("tmp_im", tmp_im)
box = np.squeeze(box).astype(np.float32) # Remove redundant dimensions
# Sorting the points order is top-left, top-right, bottom-right, bottom-left.
# Note:
# The method I am using is a bit of an "overkill".
# I am not sure if the implementation is correct.
# You may sort the corners using simple logic - find top left, bottom right, and match the other two points.
############################################################################
# Find the center of the contour
# https://docs.opencv.org/3.4/dd/d49/tutorial_py_contour_features.html
M = cv2.moments(c)
cx = M['m10']/M['m00']
cy = M['m01']/M['m00']
center_xy = np.array([cx, cy])
cbox = box - center_xy # Subtract the center from each corner
# For a square the angles of the corners are:
# -135 -45
#
#
# 135 45
ang = np.arctan2(cbox[:,1], cbox[:,0]) * 180 / np.pi # Compute the angles from the center to each corner
# Sort the corners of box counterclockwise (sort box elements according the order of ang).
box = box[ang.argsort()]
############################################################################
# Reorder points: top-left, top-right, bottom-left, bottom-right
coor = np.float32([box[0], box[1], box[3], box[2]])
return coor
original_image = cv2.imread("original_image.jpg") # Read the original image
bw_mask = cv2.imread("black_and_white_mask.jpg", cv2.IMREAD_GRAYSCALE) # Read image as Grayscale
bw_mask = cv2.threshold(bw_mask, 0, 255, cv2.THRESH_OTSU)[1] # Convert to binary image (just in case...)
# Find the corners of the mask, and sort them
orig_im_coor = find_corners(bw_mask)
# Compute width and height of the destination image according to orig_im_coor
#
width = round(np.linalg.norm(orig_im_coor[0] - orig_im_coor[1])) # Assume width is the distance from top-left to top-right
height = round(np.linalg.norm(orig_im_coor[0] - orig_im_coor[2])) # Assume height is the distance from top-left to bottom-left
#height, width = 450, 350
new_image_coor = np.float32([[0, 0], [width, 0], [0, height], [width, height]])
P = cv2.getPerspectiveTransform(orig_im_coor, new_image_coor)
#perspective = cv2.warpPerspective(input_image2, P, (width, height))
# Apply the perspective transform on the original_image
perspective = cv2.warpPerspective(original_image, P, (width, height))
cv2.imshow("Perspective transformation", perspective)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果:
更新:
在不变形的情况下裁剪遮罩区域。
这里是一个不变形裁剪的例子:
original_image = cv2.imread("original_image.jpg") # Read the original image
bw_mask = cv2.imread("black_and_white_mask.jpg", cv2.IMREAD_GRAYSCALE) # Read image as Grayscale
bw_mask = cv2.threshold(bw_mask, 0, 255, cv2.THRESH_OTSU)[1] # Convert to binary image (just in case...)
# Find the corners of the mask, and sort them
orig_im_coor = find_corners(bw_mask)
# Mask the background - place zeros where mask is zero
masked_image = cv2.bitwise_and(original_image, original_image, mask=bw_mask)
# The corners are the minimum and maximum of orig_im_coor
x0 = int(round(orig_im_coor[:, 0].min()))
y0 = int(round(orig_im_coor[:, 1].min()))
x1 = int(round(orig_im_coor[:, 0].max()))
y1 = int(round(orig_im_coor[:, 1].max()))
cropped_masked_image = masked_image[y0:y1+1, x0:x1+1, :].copy() # Crop area from top-left to bottom-right
# Show the results:
cv2.imshow('masked_image', masked_image)
cv2.imshow('cropped_masked_image', cropped_masked_image)
cv2.waitKey()
cv2.destroyAllWindows()
结果:
masked_image
:
cropped_masked_image
: