Xóa nền khỏi hình ảnh OpenCV Python

Chúng ta đang sống trong thời đại của các cuộc gọi video. Được thực hiện qua internet và sử dụng bất kỳ máy ảnh nào đi kèm với máy tính xách tay hoặc máy tính của bạn, chúng tôi phát sóng cuộc sống của mình cho bạn học, đồng nghiệp và gia đình của chúng tôi

Tuy nhiên, đôi khi chúng tôi không muốn phát sóng không gian của mình. Văn phòng của tôi, giống như nhiều văn phòng khác, có một vài thứ lộn xộn lâu năm. Tôi cũng có một cây đàn guitar trên tường phía sau, không phải lúc nào cũng thể hiện sự chuyên nghiệp

Do đó, Zoom và phần mềm gọi điện video khác bao gồm tính năng ẩn nền của bạn, thường là đằng sau hình ảnh bạn chọn. Mặc dù hầu hết không nghĩ nhiều về nó, nhưng nhiệm vụ thực tế là xác định yếu tố quyết định tiền cảnh và hậu cảnh trong một bức ảnh hầu như không hề nhỏ.

Phát hiện tiền cảnh

Phát hiện tiền cảnh là một trong những ứng dụng nổi bật nhất trong thị giác máy tính. Ngoài ví dụ về cuộc gọi video, tính năng phát hiện tiền cảnh có thể được sử dụng để tìm và đọc văn bản trong hình ảnh, xác định vị trí chướng ngại vật trong xe tự hành và nhiều ứng dụng khác

Kết quả là, nhiều phương pháp phức tạp đã được phát triển để phân biệt tiền cảnh và hậu cảnh.

OpenCV cung cấp một vài giải pháp “vượt trội”; . Thay vào đó, tôi sẽ sử dụng thuật toán được xây dựng tùy chỉnh để tận dụng một số mô-đun OpenCV để đạt được kết quả tương tự

Phát hiện cạnh và đường viền

Phương pháp tôi sẽ chứng minh là nền tảng trên hai khái niệm. phát hiện cạnh và đường viền

Phát hiện cạnh, giống như tên của nó, cố gắng tìm các đường tương phản hoặc các cạnh trong một hình ảnh. Bước quan trọng đầu tiên này sẽ xử lý trước hình ảnh để giúp phân biệt bất kỳ đối tượng nào. Có một số phương pháp phát hiện cạnh, nhưng phương pháp Canny cực kỳ phổ biến và được đóng gói cùng với OpenCV

Khi các cạnh được tìm thấy, việc tìm kiếm các đường viền trở nên dễ dàng và chính xác hơn nhiều. Trong thị giác máy tính, đường viền chỉ đơn giản là các đường ranh giới liên tục giữa các vùng có màu hoặc cường độ tương phản. Không giống như phát hiện cạnh, tìm đường viền sẽ tìm thấy các hình dạng nổi bật trong hình ảnh

thuật toán

Như đã đề cập trước đây, các công cụ xóa nền được đóng gói sẵn trong OpenCV sẽ không được sử dụng. Thay vào đó, lưu đồ bên dưới phác thảo phương pháp tôi sẽ sử dụng

Đầu tiên, chúng tôi sẽ lấy hình ảnh và chuyển đổi nó thành đen trắng. Tiếp theo, tính năng phát hiện cạnh sẽ được áp dụng và các đường viền trong ảnh sẽ được tìm thấy. Bất kỳ đường viền nào quá lớn hoặc quá nhỏ để làm nền trước sẽ bị xóa

Các đường viền còn lại sẽ được coi là tiền cảnh. Điều này có ý nghĩa trực quan, vì các chi tiết đặc biệt nhỏ trong nền bận rộn sẽ tạo ra các đường viền rất nhỏ. Ngược lại, các đường viền rất lớn chiếm phần lớn màn hình có thể không phải là tiền cảnh, mà là một số đồ tạo tác trực quan của hậu cảnh

Cuối cùng, một mặt nạ được tạo từ các đường viền còn lại và được trộn vào ảnh gốc

Thực hiện
import numpy as np
import cv2

Trước khi làm nhiều, cần nhập hai thư viện. NumPy hoạt động để làm cho một số thao tác xử lý số hiệu quả hơn. OpenCV xử lý thao tác hình ảnh

# Parameters
blur = 21
canny_low = 15
canny_high = 150
min_area = 0.0005
max_area = 0.95
dilate_iter = 10
erode_iter = 10
mask_color = (0.0,0.0,0.0)

Tiếp theo, một tập hợp các biến được chỉ định sẽ ảnh hưởng đến cách loại bỏ nền. Mỗi biến có một hiệu ứng riêng, hiệu ứng này có thể cần được tinh chỉnh dựa trên chủ đề của video. Nói ngắn gọn

  • mơ hồ. ảnh hưởng đến độ “mượt” của đường phân chia giữa hậu cảnh và tiền cảnh
  • canny_low. giá trị cường độ tối thiểu dọc theo đó các cạnh sẽ được vẽ
  • canny_high. giá trị cường độ tối đa dọc theo đó các cạnh sẽ được vẽ
  • min_area. diện tích tối thiểu mà một đường bao ở tiền cảnh có thể chiếm. Lấy giá trị từ 0 đến 1
  • max_area. diện tích tối đa mà một đường bao ở tiền cảnh có thể chiếm. Lấy giá trị từ 0 đến 1
  • dilate_iter. số lần lặp lại sự giãn nở sẽ diễn ra trên mặt nạ
  • erode_iter. số lần lặp lại xói mòn sẽ diễn ra trên mặt nạ
  • mask_color. màu của nền sau khi nó bị xóa

Một số giải thích này có thể không có ý nghĩa, nhưng chúng sẽ được giải thích thêm khi chúng xuất hiện trong mã. Trong thời gian chờ đợi, vui lòng sử dụng các giá trị được cung cấp làm giá trị mặc định để bắt đầu

# initialize video from the webcam
video = cv2.VideoCapture(0)

Tiếp theo, máy ảnh web được khởi chạy, nếu có. 0 có thể được thay thế cho đường dẫn của tệp video nếu bạn không có

while True:
ret, frame = video.read()

Một vòng lặp vô hạn được bắt đầu bằng cách đọc các khung hình từ máy ảnh. Phương thức read trả về 2 giá trị

  1. Một boolean để biết máy ảnh có hoạt động bình thường hay không, được lưu trữ trong biến ret
  2. Một khung hình thực tế từ nguồn cấp dữ liệu video, được ghi lại trong biến khung hình
    if ret == True:        # Convert image to grayscale        
image_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Apply Canny Edge Dection
edges = cv2.Canny(image_gray, canny_low, canny_high)

Mệnh đề if chỉ cho phép mã tiếp tục nếu máy ảnh quay video chính xác. Khung được hiển thị thành thang độ xám, vì vậy bước tiếp theo, phát hiện cạnh, có thể diễn ra

Đặt giá trị cường độ tối thiểu (biến số canny_low) cho biết mức độ nhạy của độ tương phản phải được phát hiện. Điều chỉnh nó quá thấp có thể dẫn đến nhiều cạnh được phát hiện hơn mức cần thiết

Đặt giá trị cường độ tối đa (biến canny_high) chỉ ra rằng bất kỳ độ tương phản nào cao hơn giá trị của nó sẽ được phân loại ngay lập tức là cạnh. Điều chỉnh nó quá cao có thể ảnh hưởng đến hiệu suất, nhưng điều chỉnh nó quá thấp có thể bỏ lỡ các cạnh quan trọng

        edges = cv2.dilate(edges, None)
edges = cv2.erode(edges, None)

Bước này hoàn toàn không bắt buộc, nhưng việc làm giãn và mài mòn các cạnh sẽ làm cho chúng rõ hơn và cho ra sản phẩm cuối cùng đẹp hơn

        # get the contours and their areas
contour_info = [(c, cv2.contourArea(c),) for c in cv2.findContours(edges, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)[1]]

Có rất nhiều thứ đang diễn ra trong dòng này, nhưng nó được viết theo cách này để thực hiện. Về cơ bản, hàm findContours của OpenCV trả về một mảng thông tin. Trong số thông tin này, chúng tôi chỉ quan tâm đến các đường viền, được lập chỉ mục ở 1

Đối với tất cả các đường bao được tìm thấy, một bộ của chính đường bao thực tế và diện tích của nó được lưu trữ trong một danh sách

        # Get the area of the image as a comparison
image_area = frame.shape[0] * frame.shape[1]

# calculate max and min areas in terms of pixels
max_area = max_area * image_area
min_area = min_area * image_area

Diện tích của hình ảnh được tính toán và sau đó diện tích tối đa và tối thiểu được xác định

Lý tưởng nhất là bước này sẽ được thực hiện bên ngoài vòng lặp, vì nó cản trở hiệu suất. Chụp một khung hình ban đầu trước khi phát trực tuyến hoặc chỉ cần biết trước kích thước của máy ảnh của bạn sẽ hiệu quả hơn. Như đã nói, để giữ cho mã đơn giản hơn một chút để trình diễn, điều này là đủ

________số 8

Tiếp theo, một mặt nạ được tạo, tại thời điểm này là ma trận 0

        # Go through and find relevant contours and apply to mask
for contour in contour_info:
# Instead of worrying about all the smaller contours, if the area is smaller than the min, the loop will break
if contour[1] > min_area and contour[1] < max_area:
# Add contour to mask
mask = cv2.fillConvexPoly(mask, contour[0], (255))

Đối với tất cả các đường viền được tìm thấy, diện tích của các đường viền được so sánh với các giá trị tối thiểu và tối đa. Nếu một đường viền lớn hơn mức tối thiểu và nhỏ hơn mức tối đa, đường viền đó sẽ được thêm vào mặt nạ

Nếu đường bao nhỏ hơn mức tối thiểu hoặc lớn hơn mức tối đa thì nó không được coi là một phần của tiền cảnh

# Parameters
blur = 21
canny_low = 15
canny_high = 150
min_area = 0.0005
max_area = 0.95
dilate_iter = 10
erode_iter = 10
mask_color = (0.0,0.0,0.0)
0

Giống như trước đây, việc làm giãn và làm mòn mặt nạ là tùy chọn về mặt kỹ thuật, nhưng tạo ra hiệu ứng thẩm mỹ hơn. Nguyên tắc tương tự áp dụng cho độ mờ Gaussian

# Parameters
blur = 21
canny_low = 15
canny_high = 150
min_area = 0.0005
max_area = 0.95
dilate_iter = 10
erode_iter = 10
mask_color = (0.0,0.0,0.0)
1

Những dòng này chuyển đổi cả mặt nạ và khung thành các loại dữ liệu cần thiết mà chúng cần để hòa trộn với nhau. Đó là một bước tiền xử lý đơn giản nhưng quan trọng

# Parameters
blur = 21
canny_low = 15
canny_high = 150
min_area = 0.0005
max_area = 0.95
dilate_iter = 10
erode_iter = 10
mask_color = (0.0,0.0,0.0)
2

Cuối cùng, mặt nạ và khung được trộn với nhau để nền được bôi đen. Dòng cuối cùng sau đó hiển thị kết quả

# Parameters
blur = 21
canny_low = 15
canny_high = 150
min_area = 0.0005
max_area = 0.95
dilate_iter = 10
erode_iter = 10
mask_color = (0.0,0.0,0.0)
3

Khi dọn dẹp vào phút cuối, một vài dòng đầu tiên tạo ra một điều kiện tồn tại. Nếu nhấn “q” trên bàn phím, nó sẽ ngắt vòng lặp và kết thúc chương trình

Cái khác kết nối lại với câu lệnh if được thực hiện trước đó về việc máy ảnh chụp chính xác khung hình. Nếu camera bị lỗi, nó cũng sẽ phá vỡ vòng lặp

Cuối cùng, khi vòng lặp bị phá vỡ, cửa sổ hiển thị hình ảnh thu được sẽ đóng lại và máy ảnh sẽ tắt

Kết quả

Nếu mọi việc suôn sẻ, một cửa sổ đầu ra sẽ được tạo hiển thị xóa nền theo thời gian thực. Mặc dù thuật toán ở đây hoạt động đủ tốt đối với nền rất đơn giản, nhưng nó có thể gặp nhiều khó khăn hơn khi phân biệt các nền phức tạp hơn đang “bận rộn” hoặc lộn xộn. Tuy nhiên, nhìn chung, nó hoạt động đủ tốt để chứng minh khái niệm

Dưới đây đưa ra trường hợp lý tưởng, nơi tôi đứng dựa vào bức tường trắng trơn

Loại bỏ nền trong thời gian thực trong hoàn cảnh lý tưởng. Video do tác giả sản xuất

Thuật toán có thể dễ dàng phân biệt bản thân tôi với bức tường. Có một số lỗi nói lắp có thể cần được làm mịn, nhưng trong lần thử đầu tiên, nó sẽ hoạt động tốt

Ngược lại, đây là kết quả cho trường hợp xấu nhất khi tôi dựa vào tủ sách

Loại bỏ nền trong điều kiện kém. Video do tác giả sản xuất

Nền quá bận rộn, chẳng hạn như tủ sách chứa đầy sách và các phụ kiện khác, sẽ gây nhầm lẫn cho thuật toán và dẫn đến kết quả kém hoàn hảo. Nó cố gắng phân biệt tiền cảnh với hậu cảnh khi những vệt lớn trên cánh tay và khuôn mặt của tôi nhấp nháy vào hậu cảnh

Tôi đã phóng đại kết quả này một chút. Tôi dựa lưng vào tủ sách, điều này sẽ khuếch đại hiệu ứng. Nếu tôi đứng xa hơn trước tủ sách, kết quả sẽ không tệ như vậy;

Trong thực tế, hầu hết các nỗ lực sẽ tạo ra thứ gì đó ở giữa trường hợp tốt nhất và trường hợp xấu nhất

kết luận

Các khái niệm đan xen về phát hiện tiền cảnh và trừ nền là một trong những khía cạnh được nghiên cứu nhiều nhất về thị giác máy tính. Trong khi có nhiều phương pháp, một ứng dụng đơn giản phát hiện cạnh và tìm đường bao trong ảnh cung cấp cơ sở tốt

Sử dụng các chức năng tích hợp sẵn của OpenCV, phương pháp được sử dụng có thể hiển thị loại bỏ nền trong thời gian thực. Trong điều kiện lý tưởng, thuật toán hoạt động gần như hoàn hảo, nhưng có thể cần một số điều chỉnh bổ sung đối với nền phức tạp hoặc bận rộn

Tôi có thể xóa nền khỏi hình ảnh không?

Để xóa nền khỏi hình ảnh trên máy tính Windows, hãy mở hình ảnh bạn muốn chỉnh sửa. Trên thanh công cụ, chọn Định dạng ảnh -> Xóa nền . Hoặc Định dạng -> Xóa. Lý lịch.

Làm cách nào để xóa nền khỏi hình ảnh theo chương trình?

Xóa nền hình ảnh theo chương trình thông qua API .
Xoăn. curl -H 'X-API-Key. CHÈN_API_KEY CỦA BẠN TẠI ĐÂY' \ -IF 'hình ảnh=@/đường dẫn/đến/tệp. jpg' \ -F 'mode=hình ảnh' \ -F 'format=jpg' \ -F 'background_color=#FFFFFF' \ -f https. //api. kéo cắt ảnh. com/v1/change-background \ -o kết quả. jpg
Nút. js. .
con trăn. .
PHP. .
BỌC LƯỚI. .
Tham chiếu API