Python 圖像分析:兩個圓圈的故事
點擊上方“小白學視覺”,選擇加"星標"或“置頂”
重磅干貨,第一時間送達 ![]()
在本文中,我們將使用 Python、OpenCV 和 matplotlib 進行圖像分析。
我們的任務是探索包含兩個不同大小的神秘圓圈的有趣圖像,并深入研究量化和可視化它們之間差異的各種方法。
所以,事不宜遲,讓我們從原始圖像開始我們的冒險:
此圖像是從 Microsoft PowerPoint 中提供的庫存圖像中精心挑選的。它迷人的設計激起了我的興趣,并激勵我使用一些對象檢測魔法?,F(xiàn)在我們已經(jīng)熟悉了我們的起點,讓我們開始這段旅程并逐步完成該過程的每個階段!
第 1 步:加載圖像并檢測圓圈
我們的首要任務是加載圖像并揭開隱藏在其中的圓圈。
為此,我們將尋求 OpenCV 庫的幫助,它配備了一套全面的圖像處理和計算機視覺任務工具。
import cv2
import numpy as np
import matplotlib.pyplot as plt
path_to_image = "/path/to/CircleImage.jpg"
image = cv2.imread(path_to_image)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
min_dist = image.shape[1] // 2
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1.5, minDist=min_dist)
if circles is not None:
circles = np.round(circles[0, :]).astype("int")
for (x, y, r) in circles:
cv2.circle(image, (x, y), r, (0, 255, 0), 4)
# Show the output image
plt.imshow(image)
plt.title("Circles Identified!")
plt.show()
else:
print("No circles found - Adjust Parameters")
加載圖像并將其轉換為灰度后,我們應用cv2.HoughCircles函數(shù)來顯示圖像中的圓圈。這個函數(shù)利用了 Hough Circle Transform,這是一種旨在檢測圖像中的圓形形狀的技術。
然后,我們在圖像上繪制檢測到的圓圈,并使用 matplotlib 揭開我們的杰作。
定位圖像中的圓形對象
這時,我突然產(chǎn)生了一種強烈的好奇心:這兩個圓圈的大小是否相同?
它讓人想起了那些玩弄我們感知的視覺錯覺圖像。因此,我們的分析仍在繼續(xù)!
第 2 步:創(chuàng)建蒙版并將其應用于圖像
我們的下一個目標是隔離我們之前檢測到的兩個圓圈。我想知道如果我們在圖像中將它們分開,是否會更容易辨別哪個圓更大。
為此,我們將制作一個僅包含兩個最小圓圈的蒙版并將其應用于圖像。
mask = np.zeros_like(gray)
for (x, y, r) in circles[:2]:
cv2.circle(mask, (x, y), r, (255, 255, 255), -1)
masked_image = cv2.bitwise_and(image, image, mask=mask)
# Show the masked image
plt.imshow(masked_image)
plt.title("Masked Image")
plt.show()
我們構造一個與原始圖像形狀相同的蒙版,然后在其上繪制兩個最小的圓圈。然后使用函數(shù)cv2.bitwise_and將蒙版應用于圖像,該函數(shù)僅保留兩個圓圈內(nèi)的像素,同時刪除所有其他像素。
隔離兩個圓圈的蒙版圖像
由此產(chǎn)生的圖像相當迷人。它喚起了地球(紅色圓圈)和它的天體伙伴月球(紫色圓圈)的形象?;蛘?,人們可能會將其視為iPhone游戲Osmos的第一關。
盡管如此,辨別這些圓圈的真實大小仍然很有挑戰(zhàn)性。讓我們使用連通分量分析來識別區(qū)域并計算兩個圓的面積(以像素為單位)。
第 3 步:查找圓形區(qū)域并裁剪圖像
為了更深入地研究兩個圓圈之間的差異,我們將計算它們的面積并裁剪它們邊界框周圍的圖像。
ret, labels = cv2.connectedComponents(mask)
regions = cv2.connectedComponentsWithStats(mask)
circle_areas = regions[2][1:3, cv2.CC_STAT_AREA]
print(f"Areas of the two circles: {circle_areas}")
這會在控制臺上打印出圓圈的面積分別為169049和145189像素!
這遠遠超過我最初的懷疑。在某些圖像分析中,例如計算機斷層掃描,像素大小與實際尺寸相關,允許我們在需要時以實際單位計算面積。
接下來,讓我們將兩個圓圈并排放置,看看是否可以清楚地識別出較大的圓圈。我們將通過裁剪圖像和填充較小的圖像來實現(xiàn)這一點,以確保準確的比例比較。
# Crop the image to the bounding box of the circle with the largest area
largest_area = np.argmax(circle_areas)
# Get the bounding box of the largest area
x, y, w, h, area = regions[2][largest_area + 1]
print(f"Bounding box of the largest circle: {x, y, w, h}")
# Crop the image to the bounding box of the circle
large_area_cropped_image = masked_image[y:y + h, x:x + w]
# Crop the image to the bounding box of the circle with the smallest area
smallest_area = np.argmin(circle_areas)
# Get the bounding box of the smallest area
x, y, w, h, area = regions[2][smallest_area + 1]
print(f"Bounding box of the smallest circle: {x, y, w, h}")
# Crop the image to the bounding box of the circle
small_area_cropped_image = masked_image[y:y + h, x:x + w]
# Pad the smaller image to the same size as the larger image
large_height, large_width = large_area_cropped_image.shape[:2]
small_height, small_width = small_area_cropped_image.shape[:2]
# Calculate padding for each side
top_padding = (large_height - small_height) // 2
bottom_padding = large_height - small_height - top_padding
left_padding = (large_width - small_width) // 2
right_padding = large_width - small_width - left_padding
# Add padding to the smaller image
small_area_cropped_image_padded = cv2.copyMakeBorder(
small_area_cropped_image,
top_padding,
bottom_padding,
left_padding,
right_padding,
cv2.BORDER_CONSTANT,
value=[0, 0, 0]
)
# Replot the images side by side
fig, ax = plt.subplots(1, 2, figsize=(10, 5))
ax[0].imshow(large_area_cropped_image)
ax[0].set_title("Largest Circle")
ax[1].imshow(small_area_cropped_image_padded)
ax[1].set_title("Smallest Circle")
# Give one title to the entire figure
fig.suptitle("Cropped Images Scaled")
plt.show()
并排繪制縮放圖像以比較區(qū)域
可視化圖像現(xiàn)在清楚地表明紅色圓圈比紫色圓圈小。
作為獎勵,讓我們嘗試將較小圖像的像素信息疊加到較大圖像上——這是我以前從未嘗試過的。我們將通過從較小的圖像復制像素值及其相關位置并將該信息繪制到較大的圓圈中來實現(xiàn)這一點。
第 4 步:將較小的圓圈放在較大的圓圈內(nèi)
我們將提取較小圓圈內(nèi)的像素值和坐標,創(chuàng)建較大圓圈圖像的副本,然后將較小圓圈繪制到較大圓圈的圖像上。此外,讓我們添加一些文本來強調(diào)這一點。
# Making a copy of the image to get the pixel values
image = small_area_cropped_image_padded.copy()
# Extract the pixel values and coordinates within the circle
circle_pixels = []
circle_coordinates = []
# Create a mask for non-black pixels
mask = np.any(image != [0, 0, 0], axis=-1)
# Get the coordinates of non-black pixels
circle_coordinates = np.argwhere(mask)
# Get the pixel values within the circle
circle_pixels = image[mask]
"""Within the large_area_cropped_image circle,
set all pixels within circle_coordinates to match circle pixels"""
# Making a copy of the image to draw on
image_copy = np.copy(large_area_cropped_image)
# Loop through the coordinates and pixel values
for (y, x), pixel in zip(circle_coordinates, circle_pixels):
# Draw the pixel onto the image copy
image_copy[y, x] = pixel
# Display the image
plt.imshow(image_copy)
plt.title("Proof: Smaller Circle in the Larger Circle")
plt.show()
# Calculate the percentage of size difference between the two circles
large_area = np.pi * (large_width / 2) ** 2
small_area = np.pi * (small_width / 2) ** 2
difference = (small_area) / large_area * 100
# Print the text "<difference>% of the size!" inside the circle
cv2.putText(
image_copy,
f"{difference:.1f}% of the size!",
(large_width // 5, large_height // 2),
cv2.FONT_HERSHEY_SIMPLEX,
1,
(255, 255, 255),
2
)
# Display the image
plt.imshow(image_copy)
plt.title("Percentage of Size")
plt.show()
我們的最終圖像分析
我們現(xiàn)在已經(jīng)完成了這個任務。這個練習展示了圖像分析的可能性,從感興趣的隨機圖像開始。我們實現(xiàn)了對象檢測、連通分量分析、面積計算,并磨練了我們在圖像轉換方面的技能。
下載1:OpenCV-Contrib擴展模塊中文版教程
在「小白學視覺」公眾號后臺回復:擴展模塊中文教程,即可下載全網(wǎng)第一份OpenCV擴展模塊教程中文版,涵蓋擴展模塊安裝、SFM算法、立體視覺、目標跟蹤、生物視覺、超分辨率處理等二十多章內(nèi)容。
下載2:Python視覺實戰(zhàn)項目52講
在「小白學視覺」公眾號后臺回復:Python視覺實戰(zhàn)項目,即可下載包括圖像分割、口罩檢測、車道線檢測、車輛計數(shù)、添加眼線、車牌識別、字符識別、情緒檢測、文本內(nèi)容提取、面部識別等31個視覺實戰(zhàn)項目,助力快速學校計算機視覺。
下載3:OpenCV實戰(zhàn)項目20講
在「小白學視覺」公眾號后臺回復:OpenCV實戰(zhàn)項目20講,即可下載含有20個基于OpenCV實現(xiàn)20個實戰(zhàn)項目,實現(xiàn)OpenCV學習進階。
交流群
歡迎加入公眾號讀者群一起和同行交流,目前有SLAM、三維視覺、傳感器、自動駕駛、計算攝影、檢測、分割、識別、醫(yī)學影像、GAN、算法競賽等微信群(以后會逐漸細分),請掃描下面微信號加群,備注:”昵稱+學校/公司+研究方向“,例如:”張三 + 上海交大 + 視覺SLAM“。請按照格式備注,否則不予通過。添加成功后會根據(jù)研究方向邀請進入相關微信群。請勿在群內(nèi)發(fā)送廣告,否則會請出群,謝謝理解~
