Hướng dẫn python copy highlighted text - python copy văn bản được đánh dấu

Tôi là một người mới của Python đang cố gắng tìm ra cách để sao chép Python bất cứ văn bản nào tôi đã nhấn mạnh khi chương trình được gọi.

Tôi đã xem xét giải pháp được đăng trong chủ đề này: Sao chép văn bản được tô sáng vào bảng tạm, sau đó sử dụng bảng tạm để nối nó vào danh sách

Tất cả mọi thứ ở đó đều có ý nghĩa về lý thuyết nhưng vấn đề là khi tôi chạy chương trình, có vẻ như lệnh 'PYA.DoubleClick (pya.poseition ())' 'Lệnh đã loại bỏ điểm nổi bật của tôi! Nếu tôi để con trỏ của mình lơ lửng trên văn bản thì chương trình sẽ làm nổi bật thành công một từ nhất định - nhưng tôi cần có khả năng sao chép toàn bộ cụm từ!

Những gì tôi muốn đạt được là có thể làm nổi bật bất kỳ văn bản nào trên màn hình (bao gồm toàn bộ cụm từ và không chỉ các từ cụ thể) và sau đó chạy chương trình với kết quả văn bản được tô sáng được cung cấp thông qua chương trình.

Tôi đã dự đoán điều này sẽ liên quan đến một số loại tự động hóa chức năng 'Ctrl' + 'C' trong khi văn bản được tô sáng ... nhưng tôi không thể nhận ra để thực sự làm việc này.

Tôi đang sử dụng Python 3.7.4 trên Windows 10.

Đây là mã được trình bày dưới dạng giải pháp trong luồng mà tôi đã liên kết ở trên:

import pyautogui as pya
import pyperclip  # handy cross-platform clipboard text handler
import time

def copy_clipboard():
    pyperclip.copy("") # <- This prevents last copy replacing current copy of null.
    pya.hotkey('ctrl', 'c')
    time.sleep(.01)  # ctrl-c is usually very fast but your program may execute faster
    return pyperclip.paste()

# double clicks on a position of the cursor
pya.doubleClick(pya.position())

list = []
var = copy_clipboard()
list.append(var) 
print(list)

Có lẽ vấn đề thực sự của tôi là tôi không biết làm thế nào để chương trình chạy mà không thoát khỏi điểm nổi bật trên bất kỳ văn bản nào được tô sáng vào thời điểm đó. Hiện tại, để gọi chương trình, tôi đang sử dụng phương pháp rất khó hiểu để tạo lối tắt cho chương trình của mình và sau đó chỉ định phím nóng vào phím tắt đó trong tab 'Thuộc tính' vào phím tắt đó.

Tôi lỗi thời khi đọc. Mặc dù tôi thích tương đương kỹ thuật số trong hầu hết mọi khía cạnh khác của cuộc sống, nhưng khi đọc, tôi hầu như luôn thích sách giấy hơn sách điện tử, PDF hoặc phương tiện điện tử khác. Tôi thích phản hồi haptic về việc đọc một cuốn sách và tiến trình trực quan mà bạn thấy mỗi khi bạn chuyển một trang khi phần còn lại của cuốn sách giảm dần ngày càng nhiều.

Tuy nhiên, ghi chú và tạo dấu trang với một cuốn sách giấy là khá tẻ nhạt. Tất nhiên, bạn có thể làm nổi bật một số đoạn văn nhất định và chụp ảnh trang đó để lưu nó trong ứng dụng của bạn chọn. Đó thực sự là những gì tôi làm. Nhưng sau đó làm thế nào để bạn tìm lại thông tin đặc biệt này? Tôi đã được truyền cảm hứng từ bài viết này bởi Shaham, trong đó anh ấy mô tả một công cụ tô sáng kỹ thuật số nhận ra và trích xuất văn bản được tô sáng trên một trang sách. May mắn thay, anh ta đã không chia sẻ nhiều mã và ứng dụng web không còn hoạt động. Thay vì sử dụng công việc của anh ấy, tôi đã thực hiện thử thách xây dựng lại thuật toán và tự thực hiện nó. Tôi không quen thuộc với bất kỳ công nghệ nào được sử dụng, vì vậy mục tiêu thực sự là học hỏi và vui chơi.

Một số từ khác

Trước khi chúng tôi bắt đầu, tôi muốn giải thích ngắn gọn cấu trúc cơ bản của bài đăng này và một vài từ về các công nghệ liên quan. Cấu trúc của bài đăng này giống với con đường tôi đi theo khi tôi đang làm việc về vấn đề này và việc thực hiện nó. Đầu tiên, để trích xuất tất cả các văn bản trên một trang sách, bất kể nó có được tô sáng hay không. Thứ hai, để tìm các phác thảo của các khu vực màu vàng nổi bật. Cuối cùng, hai phần này được hợp nhất để chỉ trích xuất văn bản nằm trong các phác thảo của một khu vực được tô sáng và do đó được tô sáng văn bản. Tôi đã thêm một số đoạn mã vào mỗi phần, nhưng chủ yếu là tài liệu tham khảo cho những người trong chúng ta thích đọc mã qua các từ. Tuy nhiên, tôi sẽ tập trung vào việc giải thích các khái niệm đằng sau việc thực hiện vì chúng có thể chuyển sang các công nghệ khác.

Nhận dạng nhân vật quang học

Nhận dạng ký tự quang học (OCR) là một quá trình trích xuất văn bản được viết hoặc in từ tài liệu - chẳng hạn như hình ảnh - và để chuyển đổi nó thành văn bản kỹ thuật số có thể được sử dụng để xử lý thêm, ví dụ: Để lập chỉ mục văn bản này trong cơ sở dữ liệu và truy cập nó thông qua công cụ tìm kiếm. Một số người có thể nhớ nỗ lực của Google để số hóa mọi cuốn sách trên hành tinh và cung cấp nó thông qua tìm kiếm Google Books của họ hoặc Project Guttenberg số hóa và cung cấp sách phạm vi công cộng.

Tôi sẽ sử dụng động cơ và thư viện Tesseract OCR, và pytesseract bao bọc Python của nó để trích xuất văn bản. Nhưng có rất nhiều thư viện ngoài kia để trích xuất văn bản từ một hình ảnh. Trong một ứng dụng trong thế giới thực, có lẽ tôi sẽ sử dụng các dịch vụ đám mây từ AWS, Google hoặc Microsoft để xử lý nhiệm vụ này.

Tầm nhìn máy tính

Tầm nhìn máy tính (CV) là một mô tả rộng về các phương pháp khác nhau để phân tích, xử lý và hiểu một hình ảnh. Nó thường được sử dụng như một bước xử lý trước hoặc xử lý hậu kỳ để cải thiện kết quả của trường hợp sử dụng dự định thực tế, ví dụ như ứng dụng của OCR.
It's often used as a pre-processing or post-processing step to improve the result of the actual intended use case, for example the application of OCR.

Tôi sẽ sử dụng thư viện OpenCV và giao diện Python của nó. OpenCV bao gồm nhiều chức năng để phát hiện đối tượng trong hình ảnh và video, học máy, xử lý hình ảnh và nhiều chức năng khác.

Trang trại động vật

Tôi đã sử dụng các trang từ trang trại động vật của George Orwell cho các ví dụ của tôi dưới đây. Kể từ năm 2021, cuốn sách này đã vào miền công cộng và do đó nội dung từ cuốn sách này có thể được chia sẻ mà không bị xâm phạm.

Trích xuất tất cả văn bản

Là bước đầu tiên, chúng tôi sẽ bắt đầu với OCR và chỉ cần trích xuất tất cả văn bản từ một hình ảnh mà không tôn trọng bất kỳ điểm nổi bật nào. Để thuật toán OCR hoạt động đúng, chúng tôi phải cung cấp một hình ảnh nhị phân. Để chuyển đổi hình ảnh gốc của chúng tôi thành nhị phân, chúng tôi sẽ xử lý trước hình ảnh thông qua ngưỡng OpenCV. Có một số phương pháp khác để cải thiện chất lượng như được mô tả trong tài liệu.

Ngưỡng

Đầu tiên, chúng ta phải tạo hình ảnh hình ảnh với một chuyển đổi không gian màu đơn giản từ RGB sang màu xám. Đây là điều kiện tiên quyết cho hoạt động thực tế. Ngưỡng là một hoạt động để tách một hình ảnh thành hai lớp pixel riêng biệt, tức là tiền cảnh và nền. Kết quả là một hình ảnh nhị phân chỉ có pixel đen và trắng và không có sắc thái màu ở giữa. Lớp tiền cảnh chứa các pixel màu trắng mang/giữ thông tin thực tế, ví dụ: các từ và chữ cái. Tôi đang sử dụng thuật toán của OTSU để tự động xác định giá trị ngưỡng tối ưu.

def threshold_image(img_src):
    """Grayscale image and apply Otsu's threshold"""
    # Grayscale
    img_gray = cv2.cvtColor(img_src, cv2.COLOR_BGR2GRAY)
    # Binarisation and Otsu's threshold
    _, img_thresh = cv2.threshold(
        img_gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

    return img_thresh, img_gray

Nhập chế độ FullScreenen EXIT Mode FullScreen

Các hình ảnh sau đây cho thấy hình ảnh gốc ở bên trái, hình ảnh thang độ xám ở giữa và hình ảnh nhị phân là ngưỡng kết quả ở bên phải.

Hướng dẫn python copy highlighted text - python copy văn bản được đánh dấu
So sánh hình ảnh ban đầu, thang độ xám và nhị phân

OCR

Sau đó, chúng ta có thể tiếp tục với việc trích xuất văn bản. Hình ảnh nhị phân (ngưỡng) là đầu vào cho OCR. Tesseract, động cơ OCR, chạy các mô hình ngôn ngữ của nó trên hình ảnh được cung cấp và trả về các chuỗi được công nhận (nghĩa là các chữ cái, từ, chữ số) và siêu dữ liệu miễn phí như các hộp giới hạn, mức độ tin cậy và thông tin bố cục trang. Một hộp giới hạn là vị trí và kích thước vật lý - đây là tọa độ X/Y cộng với chiều rộng và chiều cao - của một đối tượng trên một hình ảnh.

def extract_all(img_src):
    # Extract all text as one string
    string_ocr = pytesseract.image_to_string(
        img_thresh, lang='eng', config='--psm 6')
    # Extract all text and meta data as dictionary
    data_ocr = pytesseract.image_to_data(
        img_src, lang='eng', config='--psm 6', output_type=Output.DICT)
    # Copy source image to draw rectangles
    img_result = img_src.copy()

    # Iterate through all words
    for i in range(len(data_ocr['text'])):
        # Skip other levels than 5 (word)
        if data_ocr['level'][i] != Levels.WORD: 
            continue
        # Get bounding box position and size of word
        (x, y, w, h) = (data_ocr['left'][i], data_ocr['top']
                        [i], data_ocr['width'][i], data_ocr['height'][i])
        # Draw rectangle for word bounding box
        cv2.rectangle(img_result, (x, y), (x + w, y + h), (0,0,255), 2)

    return img_result

Nhập chế độ FullScreenen EXIT Mode FullScreen

Các hình ảnh sau đây cho thấy hình ảnh gốc ở bên trái, hình ảnh thang độ xám ở giữa và hình ảnh nhị phân là ngưỡng kết quả ở bên phải.

Hướng dẫn python copy highlighted text - python copy văn bản được đánh dấu
So sánh hình ảnh ban đầu, thang độ xám và nhị phân

OCR

Sau đó, chúng ta có thể tiếp tục với việc trích xuất văn bản. Hình ảnh nhị phân (ngưỡng) là đầu vào cho OCR. Tesseract, động cơ OCR, chạy các mô hình ngôn ngữ của nó trên hình ảnh được cung cấp và trả về các chuỗi được công nhận (nghĩa là các chữ cái, từ, chữ số) và siêu dữ liệu miễn phí như các hộp giới hạn, mức độ tin cậy và thông tin bố cục trang. Một hộp giới hạn là vị trí và kích thước vật lý - đây là tọa độ X/Y cộng với chiều rộng và chiều cao - của một đối tượng trên một hình ảnh.

Để trực quan hóa kết quả OCR, tôi đã thêm các hình chữ nhật màu đỏ cho các hộp giới hạn của chuỗi được nhận dạng trên hình ảnh gốc. Bên cạnh hình ảnh này là trích xuất văn bản thực tế từ OCR. Tôi đã in chuỗi được trả về từ Tesseract trên một hình ảnh để có thể so sánh nó trực tiếp với bản gốc. Kết quả của việc trích xuất văn bản là khá tốt, mặc dù có một số lỗi.

Hộp giới hạn từ và văn bản trích xuất

def mask_image(img_src, lower, upper):
    """Convert image from RGB to HSV and create a mask for given lower and upper boundaries."""
    # RGB to HSV color space conversion
    img_hsv = cv2.cvtColor(img_src, cv2.COLOR_BGR2HSV)
    hsv_lower = np.array(lower, np.uint8)  # Lower HSV value
    hsv_upper = np.array(upper, np.uint8)  # Upper HSV value

    # Color segmentation with lower and upper threshold ranges to obtain a binary image
    img_mask = cv2.inRange(img_hsv, hsv_lower, hsv_upper)

    return img_mask, img_hsv

Nhập chế độ FullScreenen EXIT Mode FullScreen

Các hình ảnh sau đây cho thấy hình ảnh gốc ở bên trái, hình ảnh thang độ xám ở giữa và hình ảnh nhị phân là ngưỡng kết quả ở bên phải.

Hướng dẫn python copy highlighted text - python copy văn bản được đánh dấu
So sánh hình ảnh ban đầu, thang độ xám và nhị phân

OCR

Sau đó, chúng ta có thể tiếp tục với việc trích xuất văn bản. Hình ảnh nhị phân (ngưỡng) là đầu vào cho OCR. Tesseract, động cơ OCR, chạy các mô hình ngôn ngữ của nó trên hình ảnh được cung cấp và trả về các chuỗi được công nhận (nghĩa là các chữ cái, từ, chữ số) và siêu dữ liệu miễn phí như các hộp giới hạn, mức độ tin cậy và thông tin bố cục trang. Một hộp giới hạn là vị trí và kích thước vật lý - đây là tọa độ X/Y cộng với chiều rộng và chiều cao - của một đối tượng trên một hình ảnh.

def denoise_image(img_src):
    """Denoise image with a morphological transformation."""

    # Morphological transformations to remove small noise
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
    img_denoised = cv2.morphologyEx(
        img_src, cv2.MORPH_OPEN, kernel, iterations=1)

    return img_denoised

Nhập chế độ FullScreenen EXIT Mode FullScreen

Các hình ảnh sau đây cho thấy hình ảnh gốc ở bên trái, hình ảnh thang độ xám ở giữa và hình ảnh nhị phân là ngưỡng kết quả ở bên phải.

Hướng dẫn python copy highlighted text - python copy văn bản được đánh dấu
So sánh hình ảnh trước và sau khi khử nhiễu

Trích xuất văn bản nổi bật

Cho đến nay, chúng tôi đã có thể trích xuất văn bản khỏi một hình ảnh và tách các khu vực được tô sáng khỏi phần còn lại của hình ảnh. Bây giờ chúng ta cần đặt hai phần này lại với nhau để chỉ trích xuất văn bản được tô sáng. Điều này nghe có vẻ đơn giản, nhưng có một số trở ngại trên đường đi. Tôi sẽ trải qua một vài nỗ lực.

Áp dụng mặt nạ hình ảnh

Ý tưởng đầu tiên, rõ ràng nhất là sử dụng mặt nạ hình ảnh được tạo trong chương trước và sử dụng nó để ẩn tất cả các khu vực không được chiếu sáng. Về mặt kỹ thuật, chúng tôi sẽ thực hiện một chút và hoạt động giữa hình ảnh gốc và mặt nạ hình ảnh.

def apply_mask(img_src, img_mask):
    """Apply bitwise conjunction of source image and image mask."""

    img_result = cv2.bitwise_and(img_src, img_src, mask=img_mask)

    return img_result

Nhập chế độ FullScreenen EXIT Mode FullScreen

Hình ảnh sau đây minh họa những gì hoạt động làm. Tôi đã áp dụng mặt nạ hình ảnh vào hình ảnh gốc và hình ảnh ngưỡng (nhị phân) để làm cho hiệu ứng rõ ràng hơn. Đối với OCR, chúng tôi chỉ cần áp dụng mặt nạ cho hình ảnh nhị phân.
I have applied the image mask to the original image and to the thresholded (binary) image to make the effect clearer. For OCR we would only need to apply the mask to the binary image.

Hướng dẫn python copy highlighted text - python copy văn bản được đánh dấu
Mặt nạ hình ảnh bitwise và trên hình ảnh gốc và nhị phân

Mặc dù tùy chọn này có vẻ hợp lý, nhưng nếu bạn áp dụng OCR vào hình ảnh bị che giấu này, bạn sẽ nhanh chóng thấy rằng không phải tất cả các từ có thể được nhận ra vì một số từ nhất định không được tô sáng đúng: một chữ cái có thể bị thiếu từ đầu hoặc kết thúc, hoặc Từ có thể không được đánh dấu rõ ràng.

Hộp giới hạn đường viền

Nỗ lực thứ hai của tôi là tìm ra các phác thảo của các khu vực được tô sáng bằng cách sử dụng phát hiện đường viền trên mặt nạ hình ảnh. Mỗi đường viền có một hộp giới hạn (được gọi là một trực tràng giới hạn trong openCV) mô tả vị trí và kích thước của nó. Sau đó, chúng ta có thể cắt hình ảnh theo kích thước của hộp giới hạn và chỉ áp dụng OCR vào khu vực có liên quan của hình ảnh.

def draw_contour_boundings(img_src, img_mask, threshold_area=400):
    """Draw contour bounding and contour bounding box"""
    # Contour detection
    contours, hierarchy, = cv2.findContours(
        img_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    # Create two copies of source image
    img_contour = img_src.copy()
    img_box = img_src.copy()

    for idx, c in enumerate(contours):
        # Skip small contours because its probably noise
        if  cv2.contourArea(c) < threshold_area:
            continue

        # Draw contour in red
        cv2.drawContours(img_contour, contours, idx, (0, 0, 255), 2, cv2.LINE_4, hierarchy)

        # Get bounding box position and size of contour
        x, y, w, h = cv2.boundingRect(c)
        # Draw bounding box in blue
        cv2.rectangle(img_box, (x, y), (x + w, y + h), (255, 0, 0), 2, cv2.LINE_AA, 0)

    return img_contour, img_box

Nhập chế độ FullScreenen EXIT Mode FullScreen

Hình ảnh sau đây minh họa những gì hoạt động làm. Tôi đã áp dụng mặt nạ hình ảnh vào hình ảnh gốc và hình ảnh ngưỡng (nhị phân) để làm cho hiệu ứng rõ ràng hơn. Đối với OCR, chúng tôi chỉ cần áp dụng mặt nạ cho hình ảnh nhị phân.

Hướng dẫn python copy highlighted text - python copy văn bản được đánh dấu
Mặt nạ hình ảnh bitwise và trên hình ảnh gốc và nhị phân

Mặc dù tùy chọn này có vẻ hợp lý, nhưng nếu bạn áp dụng OCR vào hình ảnh bị che giấu này, bạn sẽ nhanh chóng thấy rằng không phải tất cả các từ có thể được nhận ra vì một số từ nhất định không được tô sáng đúng: một chữ cái có thể bị thiếu từ đầu hoặc kết thúc, hoặc Từ có thể không được đánh dấu rõ ràng.

Hộp giới hạn đường viền

Nỗ lực thứ hai của tôi là tìm ra các phác thảo của các khu vực được tô sáng bằng cách sử dụng phát hiện đường viền trên mặt nạ hình ảnh. Mỗi đường viền có một hộp giới hạn (được gọi là một trực tràng giới hạn trong openCV) mô tả vị trí và kích thước của nó. Sau đó, chúng ta có thể cắt hình ảnh theo kích thước của hộp giới hạn và chỉ áp dụng OCR vào khu vực có liên quan của hình ảnh.
Going back to the first chapter, we applied OCR to the entire page. The engine returned each recognized string along with its bounding box - the position and size - on the image. From here, it's easy to calculate the area of the bounding box, as it's basically just a rectangle with two points: x1/y1 and x2/y2. With this rectangle, also called Region of Interest or ROI, we select exactly the same area on the image mask. Now, in order for a word to be considered "highlighted", we need to determine how much of its area described by its bounding box (rectangle) is white compared to its total area. This ratio can be expressed as a percentage as whitepixelstotalpixels ×100\frac{white\;pixels}{total\;pixels}\times100 and must be determined for each word. Finally, we can simply go through all the words and check if the highlighted area percentage exceeds a certain threshold, e.g. 25%. If so, the area is considered highlighted and added to the output, otherwise it is discarded.

def find_highlighted_words(img_mask, data_ocr, threshold_percentage=25):
    """Find highlighted words by calculating how much of the words area contains white pixels compared to balack pixels."""

    # Initiliaze new column for highlight indicator
    data_ocr['highlighted'] = [False] * len(data_ocr['text'])

    for i in range(len(data_ocr['text'])):
        # Get bounding box position and size of word
        (x, y, w, h) = (data_ocr['left'][i], data_ocr['top']
                        [i], data_ocr['width'][i], data_ocr['height'][i])
        # Calculate threshold number of pixels for the area of the bounding box
        rect_threshold = (w * h * threshold_percentage) / 100
        # Select region of interest from image mask
        img_roi = img_mask[y:y+h, x:x+w]
        # Count white pixels in ROI
        count = cv2.countNonZero(img_roi)
        # Set word as highlighted if its white pixels exceeds the threshold value
        if count > rect_threshold:
            data_ocr['highlighted'][i] = True

    return data_ocr

Nhập chế độ FullScreenen EXIT Mode FullScreen

Hình ảnh sau đây minh họa những gì hoạt động làm. Tôi đã áp dụng mặt nạ hình ảnh vào hình ảnh gốc và hình ảnh ngưỡng (nhị phân) để làm cho hiệu ứng rõ ràng hơn. Đối với OCR, chúng tôi chỉ cần áp dụng mặt nạ cho hình ảnh nhị phân.

Hướng dẫn python copy highlighted text - python copy văn bản được đánh dấu

Mặt nạ hình ảnh bitwise và trên hình ảnh gốc và nhị phân

Mặc dù tùy chọn này có vẻ hợp lý, nhưng nếu bạn áp dụng OCR vào hình ảnh bị che giấu này, bạn sẽ nhanh chóng thấy rằng không phải tất cả các từ có thể được nhận ra vì một số từ nhất định không được tô sáng đúng: một chữ cái có thể bị thiếu từ đầu hoặc kết thúc, hoặc Từ có thể không được đánh dấu rõ ràng.

Hộp giới hạn đường viền
If you're interested in testing it yourself, you will soon find all the code with instructions on how to run it locally in my GitHub repository. I am preparing it right now to make it available to the public.