Bảng image file list control 3ds max là gì năm 2024

Hello I was trying to make a simple multisubobject material , but whenever I go to each submaterial to add a different diffuse image, it loads a window and says select image file list contro l and sets to one and so even if I change file map for the other subobject materials it keeps using always the same image and this file, why ? and how can I get rid of it and use a different image for every single material? I remember I could do but may be I changed something and now isn't working to me?

Trong thời điểm nhà nước đang thúc đẩy mạnh mẽ quá trình chuyển đổi số như hiện nay, Document Understanding nói chung cũng như Table Extraction nói riêng đang trở thành một trong những lĩnh vực được quan tâm phát triển và chú trọng hàng đầu. Vậy Table Extraction là gì? Document Understanding là cái chi? Hãy đọc tiếp các phần bên dưới để biết thêm thông tin chi tiết!

Nói cao siêu vậy thôi, trong bài viết này, mình sẽ cùng các bạn điểm qua 1 vài điểm đáng chú ý trong 2 lĩnh vực này [thực chất là tập con - tập cha của nhau thôi] để các bạn có thể nắm được tổng quan. Sau đó, chúng ta sẽ đi sâu vào phần code trâu bò, mà cụ thể là code cho table extraction với opencv đã được mình nêu ở tiêu đề bài viết [phần được mong đợi nhất].

Oke, hãy bắt đầu tìm hiểu nội dung bằng một cái Upvote nào

1. Table Extraction

Trước khi đi vào chủ đề chính của bài viết: Table Extraction, mình muốn trình bày sơ qua 1 chút về một bài toán bao quát hơn: Document Understanding để chúng ta có một cái nhìn toàn diện và rõ ràng hơn về mảng nghiên cứu này.

1.1 Document Understanding

Một cách dễ hiểu, Document Understanding hướng đến việc trích xuất và thu thập dữ liệu từ các tài liệu khác nhau và đảm bảo xử lý tài liệu từ đầu đến cuối.

Để thực hiện điều đó, các giải pháp cần đảm bảo hoạt động với nhiều loại tài liệu khác nhau [từ có cấu trúc đến phi cấu trúc], nhận dạng các đối tượng khác nhau như bảng biểu, chữ viết tay, chữ ký hoặc checkbox cũng như có thể xử lý các định dạng tệp khác nhau [docx, pdf, image, ...].

Như gif minh họa dưới đây [source: NanoNet], một cách chung nhất, các giải pháp cho Document Understanding bao gồm 2 thành phần không thể thiếu: Robotic Process Automation [RPA] và Artificial Intelligence [AI]

Robotic Process Automation [RPA] đề cập đến những công nghệ giúp tự động hóa các tác vụ quản trị thông qua các bot phần mềm và phần cứng. Các bot này tận dụng các giao diện người dùng để nắm bắt dữ liệu và thao tác các ứng dụng như con người vẫn làm, mà không cần đến sự can thiệp trực tiếp của con người. Trong đó, Optical Character Recognition [OCR] là một trong những tính năng quan trọng được tập trung phát triển trong RPA.

Dưới đây là workflow của những công nghệ RPA nói chung. Các bạn có thể đọc 1 bài phân tích chi tiết hơn về RPA cũng như Document Understanding tại blog của NanoNet: A Comprehensive Guide to OCR with RPA and Document Understanding

1.2 Tổng quan Table Extraction

  • Định nghĩa

    Table Extraction [TE] is the task of detecting and decomposing table information in a document.

Table Extraction là 1 task con của Document Understanding, mà trong đó, tập trung chính vào nhiệm vụ tự động phát hiện, phân tích và bóc tách các thông tin trong các bảng biểu [nếu có] của tài liệu. Trong bài viết này, mình quan tâm đến các tài liệu scan, hay cụ thể hơn là tài liệu dạng ảnh.

  • Một số thử thách

    Như chúng ta đã biết, trong một tài liệu bất kì, bảng biểu [nếu có] luôn bao gồm những thông tin quan trọng về các thông số, số liệu, thống kê, ... được trình bày một cách quy củ và có cấu trúc. Trước khi đi sâu vào việc phân tích tính ứng dụng của trích xuất bảng biểu, chúng ta sẽ điểm qua một số thách thức cần chú ý trong tác vụ này

    1. Cấu trúc
      Đầu tiên, hãy nói về tính đa dạng về các thể hiện khác nhau ở bảng biểu. Trong hình trên, mình có chỉ ra 4 dạng chính có thể tồn tại của bảng trong các tài liệu khác nhau. Dạng 1 là dạng đơn giản và thường gặp nhất, có đầy đủ các đường phân cách hàng cột, không tồn tại các trường hợp merge hàng hoặc merge cột. Dạng 2 là một dạng khó hơn chút. Mặc dù vẫn không tồn tại trường hợp merging, nhưng các đường phân cách đã bị bỏ đi, thay vào đó là sử dụng các border khác nhau. Dạng 3 có thể tạm coi như trường hợp khó xử lí nhất, khi mà tồn tại việc merge nhiều hàng cũng như merge nhiều cột, gây ra những nhập nhằng trong việc phân tích và bóc tách. Dạng 4 cũng gây ra những khó khăn mới trong xử lí khi mà bảng không thẳng hoàn toàn mà đã được transform đi.
    2. Chất lượng ảnh Đây có thể nói là vấn đề chung của tất cả các tác vụ xử lí ảnh thông thường rồi. Đối với các tài liệu, văn bản scan, tùy thuộc vào chất lượng của máy in, máy scan, các hình ảnh thu được có thể tốt hoặc xấu với đa dạng chất lượng. Trong trường hợp xấu nhất, chúng ta có thể đối mặt với việc xử lí các hình ảnh mờ, độ tương phản thấp, các bảng biểu bị mất nét hoặc tệ hơn thế nữa ...
    3. Background Thông thường, với một tài liệu chứa bảng biểu bất kì, background phổ biến nhất mà chúng ta có thể thấy là chữ đen - nền trắng. Điều này khá thuận lợi cho các tác vụ xử lí ảnh. Tuy nhiên, vẫn tồn tại khả năng tài liệu chứa các background khác nhau, hoặc các watermark được đánh dấu trên tài liệu.
    4. Fonts, Format Đây là một số khó khăn trong việc trích xuất, sau khi đã xác định được vị trí của các cells trong bảng. Phông chữ thường có nhiều kiểu dáng, màu sắc và độ cao khác nhau. Một số họ phông chữ, đặc biệt là những họ phông chữ thuộc dạng chữ thảo hoặc viết tay, gây ra những khó khăn trong quá trình trích xuất. Do đó, ưu tiên sử dụng phông chữ tốt và định dạng phù hợp sẽ giúp thuật toán xác định thông tin chính xác hơn.
  • Ứng dụng

    • Mục đích cá nhân [Personal use cases]
      • Chuyển đổi văn bản scan [Scanning Documents to Phone]
      • Documents to HTML
    • Sử dụng trong công nghiệp [Industrial use cases]
      • Quản lí chất lượng [Quality Control]
      • Theo dõi tài nguyên [Track Of Assets]
    • Sử dụng trong thương mại [Business use cases]
      • Tự động trích xuất hóa đơn [Invoice Automation]
      • Tự động trích xuất biểu mẫu [Form Automation]
  • Các hướng tiếp cận chính

    • Xử lí ảnh truyền thống [OpenCV] : Dựa trên các đặc trưng về cạnh dọc và cạnh ngang của bảng biểu để tiến hành tính toán, tìm ra các contour chứa các cell của bảng
    • Image Segmentation : Sử dụng 1 mạng Encoder-Decoder tương tự như với các tác vụ segmentation thông thường, trích xuất ra mask tương ứng với vị trí của bảng, của hàng cột. Tiêu biểu của hướng xử lí này, có thể kể đến TableNet [TableNet: Deep Learning model for end-to-end Table detection and Tabular data extraction from Scanned Document Images]
    • Image Detection : Coi bài toán detect table như một vấn đề object detection thông thường. Cụ thể là sử dụng các detector khá phổ biến hiện nay như Faster RCNN, Mask RCNN, ... để phát hiện vị trí của bảng trong tài liệu. [Ví dụ: DeepDeSRT: Deep Learning for Detection and Structure Recognition of Tables in Document Images]
    • Graph Neural Network : Dựa vào tính cấu trúc giữa các cell trong bảng, GNN đang là 1 hướng nghiên cứu hứa hẹn và đạt những kết quả cao trong bài toán này: Rethinking Table Recognition using Graph Neural Networks. Để có thể làm quen với những kiến thức mới mẻ về Graph Neural Network này, các bạn có thể ghé qua và nghiên cứu một bài viết có tâm từ tác giả Phan Huy Hoàng tại : [Deep Learning] Graph Neural Network - A literature review and applications
    • Others: Ngoài ra, còn rất nhiều các ý tưởng và các cách tiếp cận khác như GAN [Extracting Tables from Documents using Conditional Generative Adversarial Networks and Genetic Algorithms], ... Chi tiết hơn về phần này, các bạn có thể ghé qua blog của NanoNet tại bài viết Table Detection, Information Extraction and Structuring using Deep Learning

2. Table Detection with opencv

2.1 Phạm vi và vấn đề cần giải quyết

  • Phạm vi

Trong phần này, mình sẽ tập trung vào 1 dạng bảng biểu. Cụ thể hơn, là các bảng biểu cần có đường phân cách. Đúng vậy, vì sử dụng opencv, các đặc trưng cạnh là những yếu tố quan trọng nhất quyết định tính chính xác của thuật toán. Do đó, dù bảng có là dạng, merge hàng, merge cột thậm chí là merge cell, miễn đảm bảo có đường phân cách rõ ràng là đủ

  • Hướng giải quyết

Mô tả đơn giản, chúng ta sẽ cố gắng xác định phương trình đường thẳng của các cạnh ngang và cạnh dọc, sau đó, tính toán tọa độ giao điểm của các đường thẳng này để tìm ra tọa độ 4 góc của bảng và cells.

Sau khi xác định được các cell, công việc tiếp theo liên quan đến các bài toán text detection và text recognize với các kí tự trong từng cell.

Để phần trình bày được rõ ràng hơn, mình sẽ lấy một ví dụ mẫu và trình bày lần lượt các bước của thuật toán áp dụng trên ví dụ này. Oke, phần nội dung chính giờ mới thực sự bắt đầu.

2.2 Tiếp cận dưới góc nhìn của opencv

  • Preprocess

Trước tiên, hãy bắt đầu với những thao tác đầu tiên: Tiền xử lí. Như mình đã trình bày các vấn đề về chất lượng ảnh trước đó, các ảnh đầu vào thường mờ và có độ tương phản thấp. Vì vậy, bước đầu tiên, hãy tăng độ tương phản và làm rõ nét ảnh.

def preprocess[img, factor: int]:
    gray = cv2.cvtColor[img, cv2.COLOR_BGR2GRAY]
    img = Image.fromarray[img]
    enhancer = ImageEnhance.Sharpness[img].enhance[factor]
    if gray.std[] < 30:
        enhancer = ImageEnhance.Contrast[enhancer].enhance[factor]
    return np.array[enhancer]

Tiếp đó, đưa ảnh về dạng nhị phân để chuẩn bị cho các bước tiếp theo. Hãy nhớ: ảnh nhị phân [binary image] - không phải ảnh xám [gray image]

gray = cv2.cvtColor[table_image, cv2.COLOR_BGR2GRAY]
thresh, img_bin = cv2.threshold[
    gray, 128, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU]
img_bin = 255-img_bin

  • Horizontal lines detection

Tiếp theo, xác định các cạnh hàng ngang bằng một hàm đơn giản cv2.getStructuringElement. Bằng việc erode và dilate các đoạn thẳng này, chúng ta có được những đường cạnh hợp lí hơn.

kernel_len = gray.shape[1]//120
hor_kernel = cv2.getStructuringElement[cv2.MORPH_RECT, [kernel_len, 1]]
image_horizontal = cv2.erode[img_bin, hor_kernel, iterations=3]
horizontal_lines = cv2.dilate[image_horizontal, hor_kernel, iterations=3]
h_lines = cv2.HoughLinesP[
    horizontal_lines, 1, np.pi/180, 30, maxLineGap=250]

Sau khi có những đoạn thẳng chắp vá tạo nên những cạnh hàng ngang, tiến hành nhóm những cạnh này lại thành các cạnh chính, chúng ta sẽ thu được những đường thẳng cạnh cần thiết

def group_h_lines[h_lines, thin_thresh]:
    new_h_lines = []
    while len[h_lines] > 0:
        thresh = sorted[h_lines, key=lambda x: x[0][1]][0][0]
        lines = [line for line in h_lines if thresh[1] -
                 thin_thresh  thresh[1] + thin_thresh]
        x = []
        for line in lines:
            x.append[line[0][0]]
            x.append[line[0][2]]
        x_min, x_max = min[x] - int[5*thin_thresh], max[x] + int[5*thin_thresh]
        new_h_lines.append[[x_min, thresh[1], x_max, thresh[1]]]
    return new_h_lines
 new_horizontal_lines = group_h_lines[h_lines, kernel_len]

  • Vertical lines detection

Tiếp đến là những thao tác tương tự đối với các cạnh hàng dọc. Khác biệt duy nhất ở đây chỉ là kernel được sử dụng ban đầu.

kernel_len = gray.shape[1]//120
ver_kernel = cv2.getStructuringElement[cv2.MORPH_RECT, [1, kernel_len]]
image_vertical = cv2.erode[img_bin, ver_kernel, iterations=3]
vertical_lines = cv2.dilate[image_vertical, ver_kernel, iterations=3]
v_lines = cv2.HoughLinesP[vertical_lines, 1, np.pi/180, 30, maxLineGap=250]

def group_v_lines[v_lines, thin_thresh]:
    new_v_lines = []
    while len[v_lines] > 0:
        thresh = sorted[v_lines, key=lambda x: x[0][0]][0][0]
        lines = [line for line in v_lines if thresh[0] -
                 thin_thresh  thresh[0] + thin_thresh]
        y = []
        for line in lines:
            y.append[line[0][1]]
            y.append[line[0][3]]
        y_min, y_max = min[y] - int[4*thin_thresh], max[y] + int[4*thin_thresh]
        new_v_lines.append[[thresh[0], y_min, thresh[0], y_max]]
    return new_v_lines
new_vertical_lines = group_v_lines[v_lines, kernel_len]

  • Get intersect point of lines

    Oke, sau khi đã có được các hình ảnh và cạnh dọc và cạnh ngang, một hướng tư duy thông thường là sử dụng hàm findContour của opencv để tự động detect cell. Tuy nhiên, mình đã thử và nhận thấy phương pháp này không thực sự đem lại hiểu quả, đặc biệt khi

    • Ảnh mờ
    • Nét cạnh của bảng đứt đoạn hoặc không rõ
    • Không bắt được hoàn toàn 100% các cells

Thay vì sử dụng Contour, trong bài viết này, mình đề xuất một phương án đơn giản, và khả thi hơn bao giờ hết.

Trước tiên, hãy bàn về tính đơn giản, tại sao mình lại bảo nó đơn giản? Thì ở đây, ý tưởng của mình base trên các bài toán giải hệ phương trình 2 ẩn cấp tiểu học. Mà cụ thể hơn là tiến hành xác định giao điểm của những cạnh dọc và cạnh ngang này để đưa ra vị trí [cụ thể là tọa độ 4 góc] của bảng và các cells.

Tiếp theo, tại sao phương án này khả thi ? Bằng việc quan tâm các giá trị đầu cuối nhắm tìm phương trình đường thẳng, phương pháp này có thể tự động fill đầy những chỗ cạnh bị đứt đoạn hoặc quá mờ. Ngoài ra, các cells cũng có thể đảm bảo 99.99% sẽ được bắt đầy đủ, không bỏ sót và được tự động sắp xếp thứ tự từ trên xuống dưới, từ trái qua phải.

def seg_intersect[line1: list, line2: list]:
    a1, a2 = line1
    b1, b2 = line2
    da = a2-a1
    db = b2-b1
    dp = a1-b1
    def perp[a]:
        b = np.empty_like[a]
        b[0] = -a[1]
        b[1] = a[0]
        return b
    dap = perp[da]
    denom = np.dot[dap, db]
    num = np.dot[dap, dp]
    return [num / denom.astype[float]]*db + b1

  • Results

points = []
for hline in new_horizontal_lines:
    x1A, y1A, x2A, y2A = hline
    for vline in new_vertical_lines:
        x1B, y1B, x2B, y2B = vline
        line1 = [np.array[[x1A, y1A]], np.array[[x2A, y2A]]]
        line2 = [np.array[[x1B, y1B]], np.array[[x2B, y2B]]]
        x, y = seg_intersect[line1, line2]
        if x1A 

Chủ Đề