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_Background_Computer Vision_Image Editing - Fatal编程技术网

如何在Python中从图片的其余部分剪切绿色背景和前景?

如何在Python中从图片的其余部分剪切绿色背景和前景?,python,opencv,background,computer-vision,image-editing,Python,Opencv,Background,Computer Vision,Image Editing,我正在尝试用绿色背景剪切多幅图像。图片的中心是绿色的,我想把图片的其余部分剪掉。问题是,我从一个视频中得到了这些图片,所以有时绿色中心更大,有时更小。我真正的任务是在结上使用K-Means,因此我有一个绿色背景和两条绳子,一条蓝色,一条红色 我将python与opencv、numpy和matplotlib结合使用 我已经剪了中间部分,但有时剪得太多,有时剪得太少。在本例中,我的图像大小为1920 x 1080 以下是我目前的代码: import numpy as np import cv2 im

我正在尝试用绿色背景剪切多幅图像。图片的中心是绿色的,我想把图片的其余部分剪掉。问题是,我从一个视频中得到了这些图片,所以有时绿色中心更大,有时更小。我真正的任务是在结上使用K-Means,因此我有一个绿色背景和两条绳子,一条蓝色,一条红色

我将python与opencv、numpy和matplotlib结合使用

我已经剪了中间部分,但有时剪得太多,有时剪得太少。在本例中,我的图像大小为1920 x 1080

以下是我目前的代码:

import numpy as np
import cv2
import matplotlib.pyplot as plt
from PIL import Image, ImageEnhance

img = cv2.imread('path')

print(img.shape)

imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

crop_img = imgRGB[500:500+700, 300:300+500]

plt.imshow(crop_img)
plt.show()

第一步是从图像中提取绿色通道,这在OpenCV numpy中很容易,并且可以生成灰度图像2D numpy阵列

import numpy as np
import cv2
img = cv2.imread('knots.png')
imgg = img[:,:,1] #extracting green channel 
第二步是使用阈值,这意味着将灰度图像转换为OpenCV具有就绪功能的纯黑白二值图像:

现在imgt是2D numpy阵列,仅由0和255组成。现在,您必须决定如何寻找切割位置,我建议如下:

包含至少50%的255像素的最上面一行 包含至少50%的255像素的最底行 像素最左边的列,包含至少50%的255 像素最右边的列,包含至少50%的255 现在,我们必须计算每行和每列中出现的次数

height = img.shape[0]
width = img.shape[1]
columns = np.apply_along_axis(np.count_nonzero,0,imgt)
rows = np.apply_along_axis(np.count_nonzero,1,imgt)
现在,列和行是1D numpy数组,每个列/行包含255个数组,知道高度和宽度后,我们可以通过以下方式获得布尔值的1D numpy数组:

columns = columns>=(height*0.5)
rows = rows>=(width*0.5)
这里0.5表示前面提到的50%,请根据您的需要随意调整该值。现在是在列和行中查找第一个True和最后一个True的索引的时候了

icolumns = np.argwhere(columns)
irows = np.argwhere(rows)
leftcut = int(min(icolumns))
rightcut = int(max(icolumns))
topcut = int(min(irows))
bottomcut = int(max(irows))
使用argwhere,我得到了Trues的numpy1d索引数组,然后找到了最低和最高索引。最后,您可以剪辑图像并保存它

imgout = img[topcut:bottomcut,leftcut:rightcut]
cv2.imwrite('out.png',imgout)
有两个地方可能需要调整:在我的示例中为255s的百分比为50%,在cv2.threshold中为阈值127


编辑:使用cv2固定线路。阈值

您可以将颜色更改为hsv

src = cv2.imread('path')
imgRGB = cv2.cvtColor(src, cv2.COLOR_BGR2RGB)
imgHSV = cv2.cvtColor(imgRGB, cv2.COLOR_BGR2HSV)
然后使用inRange仅查找绿色值

lower = np.array([20, 0, 0])    #Lower values of HSV range; Green have Hue value equal 120, but in opencv Hue range is smaler [0-180]
upper = np.array([100, 255, 255])  #Uppervalues of HSV range
imgRange = cv2.inRange(imgHSV, lower, upper)
然后使用形态学操作填充非绿线后的孔

#kernels for morphology operations
kernel_noise = np.ones((3,3),np.uint8) #to delete small noises
kernel_dilate = np.ones((30,30),np.uint8)  #bigger kernel to fill holes after ropes
kernel_erode = np.ones((38,38),np.uint8)  #bigger kernel to delete pixels on edge that was add after dilate function

imgErode = cv2.erode(imgRange, kernel_noise, 1)
imgDilate = cv2.dilate(imgErode , kernel_dilate, 1)
imgErode = cv2.erode(imgDilate, kernel_erode, 1)
在结果图像上放置遮罩。现在,您可以轻松找到绿色屏幕FindOntours函数的角点,或在下一步结果图像中使用

res = cv2.bitwise_and(imgRGB, imgRGB, mask = imgErode)  #put mask with green screen on src image

下面的代码符合您的要求。首先,它将图像转换为HSV颜色空间,这使得选择颜色更容易。接下来,制作一个仅选择绿色部分的遮罩。删除一些噪波并汇总行和列。最后,根据绿色选择中的第一行/最后一行/列创建一个新图像

因为在所有提供的示例中,需要裁剪顶部的一点额外部分,所以我添加了相应的代码。首先我把面具倒过来。现在,您可以使用行/列的总和来查找完全位于绿色选择中的行/列。它是为顶部而做的。在窗口下方的图像中,“Roi2”是最终图像

编辑:ts注释后更新的代码。 更新结果:

代码:


根据您添加的新图像,我假设您不仅希望按照您的要求剪切非绿色部分,而且希望绳索/绳结周围的框架更小。对吗?如果没有,您应该上传视频,并进一步描述裁剪的目的/目标,以便我们能够更好地帮助您

假设你想要一个只有绳子的裁剪图像,解决方案与前面的答案非常相似。但是,这次使用HSV选择绳索的红色和蓝色。根据生成的遮罩裁剪图像。如果你想让图像比绳子大一些,你可以增加额外的边距,但一定要考虑/检查图像的边缘

注意:下面的代码适用于具有全绿色背景的图像,因此我建议您将其与仅选择绿色区域的解决方案之一结合使用。我对你的所有图片进行了如下测试:我从我的另一个答案中提取代码,将其放入一个函数中,并在最后添加了return roi2。该输出被输入到保存以下代码的第二个函数中。所有图像均成功处理

结果:

代码:


你能添加示例图像吗:一个是你正在处理的图像,另一个是你想要的输出吗?添加一个到目前为止你所做的事情的最小代码。是的,我会的。我是新来的,所以我不知道怎么上传图片,但是现在你可以看到了。非常感谢!在带有两个参数0和imgt的np.count_nonzero的行中,我得到了一个错误:numpy.core。_internal.AxisError:axis 0超出了维度为0的数组的界限现在它可以工作了,但不幸的是不是一直都可以。我上传了新的图片,但效果并不完美。但也许它并没有得到一个完美的配额…我的方法是去除多余的非绿色区域,这些区域在上面,下面,到下面
绿色画布的左侧或右侧。因此,这张图片不需要剪裁:而且这张图片可能需要剪裁,但需要远远超过我理解的50%的值。谢谢,谢谢!我工作得很好。但问题是图片,我不需要剪切任何东西。该算法仍然剪切图片,只显示没有绳索的绿色部分。有时第一排绿色的是底部没有绳子的那排……我明白了。我更新代码,只查看第一列和最后一列。这应该行得通,因为绿色区域似乎有直边。谢谢!它工作得很好。但也有一些例子,它并不完美。我认为这是底部。比如我上传的最后一张照片。顶部切割完美,底部仍有棕色部分。还有右边。因为你似乎知道opencv和HSV:你知道一个简单的方法来获得完整的HSV色调值范围吗?在Matlab中,范围为0-1(双精度)。如果我在opencv中转换它,范围是0-179,或者如果我使用HSV_FULL,那么范围是0-255。但是我想要完整的范围而不丢失数据。我不太理解这个问题,但是你在opencv的范围上是正确的。获取我个人使用的从0,0,0到179255255的完整范围。非常感谢!您能告诉我如何使用findContours函数吗?我在文档中尝试过,但是im2图片不是我想要的。。。你知道一种简单的方法在python中获得完整的HSV色调值范围吗?在Matlab中,范围为0-1(双精度)。如果我在opencv中转换它,范围是0-179,或者如果我使用HSV_FULL,那么范围是0-255。但是我想要完整的范围而不丢失数据。
res = cv2.bitwise_and(imgRGB, imgRGB, mask = imgErode)  #put mask with green screen on src image
import numpy as np 
import cv2

# load image
img = cv2.imread("gr.png")
# convert to HSV
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) 
# set lower and upper color limits
lower_val = (30, 0, 0)
upper_val = (65,255,255)
# Threshold the HSV image to get only green colors
# the mask has white where the original image has green
mask = cv2.inRange(hsv, lower_val, upper_val)
# remove noise
kernel =  np.ones((8,8),np.uint8)
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)

# sum each row and each volumn of the image
sumOfCols = np.sum(mask, axis=0)
sumOfRows = np.sum(mask, axis=1)

# Find the first and last row / column that has a sum value greater than zero, 
# which means its not all black. Store the found values in variables
for i in range(len(sumOfCols)):
    if sumOfCols[i] > 0:
        x1 = i
        print('First col: ' + str(i))
        break

for i in range(len(sumOfCols)-1,-1,-1):
    if sumOfCols[i] > 0:
        x2 = i
        print('Last col: ' + str(i))
        break

for i in range(len(sumOfRows)):
    if sumOfRows[i] > 0:
        y1 = i
        print('First row: ' + str(i))
        break

for i in range(len(sumOfRows)-1,-1,-1):
    if sumOfRows[i] > 0:
        y2 = i
        print('Last row: ' + str(i))
        break

# create a new image based on the found values
#roi = img[y1:y2,x1:x2]

#show images
#cv2.imshow("Roi", roi)



# optional: to cut off the extra part at the top:
#invert mask, all area's not green become white
mask_inv = cv2.bitwise_not(mask)
# search the first and last column top down for a green pixel and cut off at lowest common point
for i in range(mask_inv.shape[0]):
    if mask_inv[i,0] == 0 and mask_inv[i,x2] == 0:
        y1 = i
        print('First row: ' + str(i))
        break

# create a new image based on the found values
roi2 = img[y1:y2,x1:x2]

cv2.imshow("Roi2", roi2)
cv2.imwrite("img_cropped.jpg", roi2)
cv2.waitKey(0)
cv2.destroyAllWindows()
import numpy as np 
import cv2

# load image
img = cv2.imread("image.JPG")
# blue
lower_val_blue = (110, 0, 0)
upper_val_blue = (179,255,155)
# red
lower_val_red = (0, 0, 150)
upper_val_red = (10,255,255)
# Threshold the HSV image
mask_blue = cv2.inRange(img, lower_val_blue, upper_val_blue)
mask_red = cv2.inRange(img, lower_val_red, upper_val_red)
# combine masks
mask_total = cv2.bitwise_or(mask_blue,mask_red)

# remove noise
kernel =  np.ones((8,8),np.uint8)
mask_total = cv2.morphologyEx(mask_total, cv2.MORPH_CLOSE, kernel)

# sum each row and each volumn of the mask
sumOfCols = np.sum(mask_total, axis=0)
sumOfRows = np.sum(mask_total, axis=1)

# Find the first and last row / column that has a sum value greater than zero, 
# which means its not all black. Store the found values in variables
for i in range(len(sumOfCols)):
    if sumOfCols[i] > 0:
        x1 = i
        print('First col: ' + str(i))
        break

for i in range(len(sumOfCols)-1,-1,-1):
    if sumOfCols[i] > 0:
        x2 = i
        print('Last col: ' + str(i))
        break

for i in range(len(sumOfRows)):
    if sumOfRows[i] > 0:
        y1 = i
        print('First row: ' + str(i))
        break

for i in range(len(sumOfRows)-1,-1,-1):
    if sumOfRows[i] > 0:
        y2 = i
        print('Last row: ' + str(i))
        break

# create a new image based on the found values
roi = img[y1:y2,x1:x2]

#show image
cv2.imshow("Result", roi)
cv2.imshow("Image", img)

cv2.waitKey(0)
cv2.destroyAllWindows()