英文:
How to crop an image with upto 6 tissue samples using OpenCV?
问题
我有一个来自公共数据集的图像(示例如下)。我想使用工具将两个组织样本分开,以增加数据集中的实例数量。数据集中的其他图像最多有6个组织。是否可以使用OpenCV来实现这一点?也欢迎其他工具。
我尝试过从一篇博客中找到的方法,但它只是在整个图像周围创建了一个边界框。也许阈值方案效果不好。
import cv2
# 读取输入图像
img = cv2.imread('pic.png')
# 将图像转换为灰度
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 在灰度图像上应用阈值处理以创建二进制图像
ret, thresh = cv2.threshold(gray, 127, 255, 0)
# 查找轮廓
contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 获取第一个轮廓
cnt = contours[0]
# 计算轮廓的边界矩形
x, y, w, h = cv2.boundingRect(cnt)
# 绘制轮廓
gray = cv2.drawContours(gray, [cnt], 0, (0, 255, 255), 2)
# 绘制边界矩形
gray = cv2.rectangle(gray, (x, y), (x+w, y+h), (0, 255, 0), 2)
# 显示带有绘制边界矩形的图像
cv2.imshow("Bounding Rectangle", gray)
cv2.waitKey(0)
cv2.destroyAllWindows()
英文:
I have an image from a public dataset (sample show below). I want to separate the two tissue samples using a tool to increase the number of instances in the dataset. Other images in the dataset have upto 6 tissues. Is there I can do that using OpenCV? Other tools are also welcomed.
I tried this from one of the blogs I came across but it just creates a bounding box around the entire image. Maybe the thresholding scheme doesn't work well
import cv2
# read the input image
img = cv2.imread('pic.png')
# convert the image to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# apply thresholding on the gray image to create a binary image
ret,thresh = cv2.threshold(gray,127,255,0)
# find the contours
contours, _ = cv2.findContours(gray,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
# take the first contour
cnt = contours[0]
# compute the bounding rectangle of the contour
x,y,w,h = cv2.boundingRect(cnt)
# draw contour
gray = cv2.drawContours(gray,[cnt],0,(0,255,255),2)
# draw the bounding rectangle
gray = cv2.rectangle(gray,(x,y),(x+w,y+h),(0,255,0),2)
# display the image with bounding rectangle drawn on it
cv2.imshow("Bounding Rectangle", gray)
cv2.waitKey(0)
cv2.destroyAllWindows()
答案1
得分: 1
以下是翻译好的代码部分:
# 导入OpenCV库
import cv2
# 读取输入图像
img = cv2.imread('pic.png')
# 将图像转换为灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 在灰度图上应用阈值处理以创建二值图像
# ret, thresh = cv2.threshold(gray, 127, 255, 0)
# ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY_INV) # 反转极性 - findContours需要白色轮廓
ret, thresh = cv2.threshold(gray, 230, 255, cv2.THRESH_BINARY_INV) # 反转极性 - findContours需要白色轮廓
# 在cv2.findContours之前考虑添加形态学闭运算。
# 查找轮廓
# contours, _ = cv2.findContours(gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # 为什么使用灰度图?
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 使用RETR_EXTERNAL而不是RETR_TREE - 我们不想找到嵌套的轮廓,只需外部轮廓
# 取第一个轮廓
# cnt = contours[0] # 为什么是第一个?第一个可能是微小的轮廓
gray_as_bgr = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR) # 在绘制之前准备BGR图像
# 迭代所有轮廓
for cnt in contours:
area = cv2.contourArea(cnt) # 计算面积
if area > 1000: # 忽略像素少于1000的轮廓 - 被视为噪声。
# 计算轮廓的边界矩形
x, y, w, h = cv2.boundingRect(cnt)
# 绘制轮廓
gray_as_bgr = cv2.drawContours(gray_as_bgr, [cnt], 0, (0, 255, 255), 2)
# 绘制边界矩形
gray_as_bgr = cv2.rectangle(gray_as_bgr, (x, y), (x+w, y+h), (0, 255, 0), 2) # 绘制绿色矩形
# 显示带有绘制的边界矩形的图像
cv2.imshow("thresh", thresh)
cv2.imshow("Bounding Rectangle", gray_as_bgr)
cv2.waitKey(0)
cv2.destroyAllWindows()
这是您提供的代码的翻译部分。
英文:
There are multiple issues:
-
findContours
expects white contours on black background - we have to invert polarity (and also select higher threshold):ret, thresh = cv2.threshold(gray, 230, 255, cv2.THRESH_BINARY_INV)
-
contours, _ = cv2.findContours(gray
is a bug - it should becontours, _ = cv2.findContours(thresh
(find contours inthresh
). -
Use
cv2.RETR_EXTERNAL
instead ofcv2.RETR_TREE
- we don't want to find nested contours, only the outer contour:contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
-
cnt = contours[0]
return the first contour that may be tiny, we have to iterate all contours. -
We better filter contours by area - ignore small contours that are considered to be noise.
Code sample:
import cv2
# read the input image
img = cv2.imread('pic.png')
# convert the image to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# apply thresholding on the gray image to create a binary image
#ret, thresh = cv2.threshold(gray, 127, 255, 0)
#ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY_INV) # Invert polarity - findContours expects white contours
ret, thresh = cv2.threshold(gray, 230, 255, cv2.THRESH_BINARY_INV) # Invert polarity - findContours expects white contours
# Consider adding morphological closing before cv2.findContours.
# find the contours
#contours, _ = cv2.findContours(gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # Why gray?
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # Use RETR_EXTERNAL instead of RETR_TREE - we don't want to find nested contours, only the outer contour
# take the first contour
#cnt = contours[0] # Why the first? The fist may be a tiny contour
gray_as_bgr = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR) # Prepare BGR image before drawing
# Iterate all contours
for cnt in contours:
area = cv2.contourArea(cnt) # Compute the area
if area > 1000: # Ignore contours with less than 1000 pixels - considered to be noise.
# compute the bounding rectangle of the contour
x, y, w, h = cv2.boundingRect(cnt)
# draw contour
gray_as_bgr = cv2.drawContours(gray_as_bgr, [cnt], 0, (0, 255, 255), 2)
# draw the bounding rectangle
gray_as_bgr = cv2.rectangle(gray_as_bgr, (x, y), (x+w, y+h), (0, 255, 0), 2) # Draw green rectangles
# display the image with bounding rectangle drawn on it
cv2.imshow("thresh", thresh)
cv2.imshow("Bounding Rectangle", gray_as_bgr)
cv2.waitKey(0)
cv2.destroyAllWindows()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论