Tìm ảnh trùng nhau bằng VBA

Liên hệ QC

MỹHạnhCB

Đi mây, về gió. !!!
Tham gia
25/3/22
Bài viết
123
Được thích
18
Chào các anh chị trong diễn đàn GPE.
Em muốn hỏi là trong VBA có thuật toán chạy kiểm tra hình ảnh giống nhau không ạ? Nếu có, có thể có em xin để tham khảo ạ. Em xin cảm ơn nhiều.
"Theo như yêu cầu là chạy thư mục chứa ảnh (1) -> So sánh ảnh trong thư mục (1) -> Phát hiện từ ảnh 2,3,4 bị trùng (giống nhau) -> Báo cáo kết quả ra Excel"
 

File đính kèm

  • 1.zip
    5.4 MB · Đọc: 34
Với vấn đề 1 Maika8008 nêu thì nghĩa là phải trong "điều kiện lý tưởng" phù hợp với khả năng giải quyết của Maika8008 chứ với các tình huống hỗn độn thì sẽ ra sao nhỉ? Vấn đề thứ 2 là có sự sai khác một vài byte giữa 2 ảnh trùng nhau khiến việc sàng lọc bị sai sót và đây là nguyên do đáng kể khiến anh chủ topic bỏ phương án của tôi mà theo phương án của Maika8008. Tuy nhiên có vẻ phương án của Maika8008 cũng đang bị vấn đề này và chắc không có phương án khắc phục.

Nếu không ngại dư luận, anh chủ topic chắc phải quay lại phương án của tôi vì nó cho phép sai số. Và có một điều nữa là phương án của tôi vẫn rộng cửa nâng cấp để đạt độ chính xác tốt hơn nữa. Còn riêng về hiệu năng, tôi bảo đảm sẽ có sự kinh ngạc về thời gian thực thi so với con số ước lượng hơn 300s của code Maika8008 trên máy tôi hiện tại.
Hỗn độn thì chạy toàn bộ folder hình thôi. Pha cà phê uống trong khi chờ vậy.

Tôi cũng đâu có đi tìm phương án tối ưu cho vấn đề của thớt, chỉ là chạy được với kết quả chính xác (tất nhiên tôi tim vào sự chính xác của code băm) là được. Lâu mau 1 tí có sao.
Bài đã được tự động gộp:

Còn nếu excel dừng lại ở đó thì em xin phép anh maika8008 ở bài #63 có thể làm thêm ở (tool .exe của python tìm ảnh trùng và báo(xuất) ra file excel) để em có thể kiểm tra được không ạ. Cảm ơn a nhiều
Bạn chạy file exe kia thử mất bao lâu (rất tiếc là file đó không báo thời gian chạy nhỉ) rồi kiểm tra tên trong thư mục để biết file nào bị đổi tên là bị trùng.
 
Lần chỉnh sửa cuối:
Upvote 0
Hỗn độn thì chạy toàn bộ folder hình thôi. Pha cà phê uống trong khi chờ vậy.

Tôi cũng đâu có đi tìm phương án tối ưu cho vấn đề của thớt, chỉ là chạy được với kết quả chính xác (tất nhiên tôi tim vào sự chính xác của code băm) là được. Lâu mau 1 tí có sao.
Bài đã được tự động gộp:


Bạn chạy file exe kia thử mất bao lâu (rất tiếc là file đó không báo thời gian chạy nhỉ) rồi kiểm tra tên trong thư mục để biết file nào bị đổi tên là bị trùng.
Vâng đúng rồi anh, file exe em nhập đường dẫn rồi cái nó tắt luôn, em cũng không biết là nó chạy chưa(hoặc chạy xong chưa) nó không báo. Chỉ khi nào có ảnh trùng, vào trong thư mục mới biết được. :D
 
Upvote 0
Vâng đúng rồi anh, file exe em nhập đường dẫn rồi cái nó tắt luôn, em cũng không biết là nó chạy chưa(hoặc chạy xong chưa) nó không báo. Chỉ khi nào có ảnh trùng, vào trong thư mục mới biết được. :D
Tôi mới vừa chạy và đếm thời gian chạy thì thấy mất tầm 30 giây cho 8 file (lâu quá) và rất tiếc là nó không duyệt tìm vào được thư mục con.
 
Upvote 0
Tôi mới vừa chạy và đếm thời gian chạy thì thấy mất tầm 30 giây cho 8 file (lâu quá) và rất tiếc là nó không duyệt tìm vào được thư mục con.
Em khai báo thêm cho bPic(i, 1) = Arr(i, 3)
Chạy dòng này :

If Not dic.Exists(aPic(i, 1)) And dic.Exists(bPic(i, 1)) Then
j = j + 1
dic.Add aPic(i, 1), j

Else
k = k + 1
aRes(k, 1) = Arr(i, 1) & "\" & Arr(i, 2)
End If

Thì nó không nhận điều kiện (If not) vậy anh, anh xem giúp em ạ.
Bài đã được tự động gộp:

Em khai báo thêm cho bPic(i, 1) = Arr(i, 3)
Chạy dòng này :

If Not dic.Exists(aPic(i, 1)) And dic.Exists(bPic(i, 1)) Then
j = j + 1
dic.Add aPic(i, 1), j

Else
k = k + 1
aRes(k, 1) = Arr(i, 1) & "\" & Arr(i, 2)
End If

Thì nó không nhận điều kiện (If not) vậy anh, anh xem giúp em ạ.
Kiểu như em cho thêm điều kiện trùng size nữa á anh. Cho thêm phần chắc chắn :p
 

File đính kèm

  • TimHinhTrungNhau_ToanNDQ.xlsm
    36.1 KB · Đọc: 6
Lần chỉnh sửa cuối:
Upvote 0
Em khai báo thêm cho bPic(i, 1) = Arr(i, 3)
Chạy dòng này :

If Not dic.Exists(aPic(i, 1)) And dic.Exists(bPic(i, 1)) Then
j = j + 1
dic.Add aPic(i, 1), j

Else
k = k + 1
aRes(k, 1) = Arr(i, 1) & "\" & Arr(i, 2)
End If

Thì nó không nhận điều kiện (If not) vậy anh, anh xem giúp em ạ.
Bài đã được tự động gộp:


Kiểu như em cho thêm điều kiện trùng size nữa á anh. Cho thêm phần chắc chắn :p
Bạn đặt điều kiện vậy không đúng đâu. Nếu muốn lấy cả 2 chuỗi làm key cho dictionary thì bạn phải nối chúng lại như sau:
If Not dic.Exists(aPic(i, 1) & "-" & bPic(i, 1)) Then.
 
Upvote 0
Tôi xin mượn một câu chuyện để liên hệ với hai tình huống giải quyết vấn đề của chủ topic.

Tại một xã hẻo lảnh nọ xẩy ra một vụ cướp. Hung thủ trong lúc tháo chạy có đánh rơi một cái mũ có vài cọng tóc. Người ta xác định được là hung thủ chắc chắn là một trong số 10000 người sống tại cái xã này.
  1. Anh điều tra viên trẻ nêu cao kiến "Chỉ cần áp dụng công nghệ ADN tân tiến, tiến hành xét nghiệp toàn bộ tóc 10000 dân xã thì chắc chắn tên cướp sẽ không thể thoát được".
  2. Anh điều tra viên trung niên thì lại trầm ngâm "Bỏ công làm 10000 mẫu xét nghiệm ADN chắc cả năm chưa xong". Thế rồi anh quay sang nạn nhân cố tìm manh mối. Vì bị tấn công bất ngờ và trong trời nhập nhoạng nên nạn nhận chỉ nhớ là tên cướp đi cà nhắc. Thế là anh điều tra viên lọc ra tất cả những người trong xã đang đi cà nhắc và tìm ra 2 người khả nghi. Anh điều tra viên lại tìm gặp nạn nhân và hỏi "Chị có nhớ đặc điểm gì đặc biệt của tên cướp không, hắn cao tầm bao nhiêu, giọng nói thế nào?". Nạn nhân nhớ ra là tên này nói lắp. Thế là người ta dễ dàng tóm được tên cướp trong số 2 người cà nhắc.
Trường hợp dùng hàm băm chả khác gì dùng công nghệ ADN tân tiến để truy ra kẻ khả nghi duy nhất vậy. Dù rất chính xác nhưng cũng rất lâu. Còn nếu dùng nhận dạng đi cà nhắc, thì ngay lập tức sàng lọc được 2 đối tượng khả nghi - tức là sẽ có 1 đối tượng vô tội (sai số). Tiếp tục áp dụng thêm 1 điều kiện nhận dạng là tật nói lắp, người ta cuối cùng tóm được đúng tên cướp.

Phương cách của tôi cũng giống như cách truy tìm [2], nó cho ra một đáp án (có thể) có sai số nhưng nếu kết hợp thêm một điều kiện sàng lọc nữa thì sẽ tìm ra kết quả chính xác. Vậy thì những file có kích cỡ tương đồng sẽ là đối tượng có nguy cơ trùng cao và tôi sẽ lại đối chiếu thêm một thuộc tính nào của chúng để xác định. Chúng ta có thể dùng "Date Taken" hoặc "Date Modified" hoặc thuộc tính nào đó đối chiếu.

Xin nhắc lại kết quả phân tích trước đây của tôi sau khi thực nghiệm với hàm FileToSHA1Hex
  1. Hàm GetFileBytes() chiếm khoảng 20% thời gian (với HDD Thì tỷ lệ % có thể cao hơn)
  2. Hàm ComputeHash_2() ngốn tới 80% thời gian.
Nếu kỹ càng hơn, chúng ta sẽ dùng kết quả từ GetFileBytes() đối chiếu một số byte ở một số ví trị nhất định trong 2 file và độ chính xác sẽ tiệm cận với hàm băm nhưng lại rút ngắn đi gần 80% thời gian thực thi code.
 
Upvote 0
Tôi xin mượn một câu chuyện để liên hệ với hai tình huống giải quyết vấn đề của chủ topic.

Tại một xã hẻo lảnh nọ xẩy ra một vụ cướp. Hung thủ trong lúc tháo chạy có đánh rơi một cái mũ có vài cọng tóc. Người ta xác định được là hung thủ chắc chắn là một trong số 10000 người sống tại cái xã này.
  1. Anh điều tra viên trẻ nêu cao kiến "Chỉ cần áp dụng công nghệ ADN tân tiến, tiến hành xét nghiệp toàn bộ tóc 10000 dân xã thì chắc chắn tên cướp sẽ không thể thoát được".
  2. Anh điều tra viên trung niên thì lại trầm ngâm "Bỏ công làm 10000 mẫu xét nghiệm ADN chắc cả năm chưa xong". Thế rồi anh quay sang nạn nhân cố tìm manh mối. Vì bị tấn công bất ngờ và trong trời nhập nhoạng nên nạn nhận chỉ nhớ là tên cướp đi cà nhắc. Thế là anh điều tra viên lọc ra tất cả những người trong xã đang đi cà nhắc và tìm ra 2 người khả nghi. Anh điều tra viên lại tìm gặp nạn nhân và hỏi "Chị có nhớ đặc điểm gì đặc biệt của tên cướp không, hắn cao tầm bao nhiêu, giọng nói thế nào?". Nạn nhân nhớ ra là tên này nói lắp. Thế là người ta dễ dàng tóm được tên cướp trong số 2 người cà nhắc.
Trường hợp dùng hàm băm chả khác gì dùng công nghệ ADN tân tiến để truy ra kẻ khả nghi duy nhất vậy. Dù rất chính xác nhưng cũng rất lâu. Còn nếu dùng nhận dạng đi cà nhắc, thì ngay lập tức sàng lọc được 2 đối tượng khả nghi - tức là sẽ có 1 đối tượng vô tội (sai số). Tiếp tục áp dụng thêm 1 điều kiện nhận dạng là tật nói lắp, người ta cuối cùng tóm được đúng tên cướp.

Phương cách của tôi cũng giống như cách truy tìm [2], nó cho ra một đáp án (có thể) có sai số nhưng nếu kết hợp thêm một điều kiện sàng lọc nữa thì sẽ tìm ra kết quả chính xác. Vậy thì những file có kích cỡ tương đồng sẽ là đối tượng có nguy cơ trùng cao và tôi sẽ lại đối chiếu thêm một thuộc tính nào của chúng để xác định. Chúng ta có thể dùng "Date Taken" hoặc "Date Modified" hoặc thuộc tính nào đó đối chiếu.

Xin nhắc lại kết quả phân tích trước đây của tôi sau khi thực nghiệm với hàm FileToSHA1Hex
  1. Hàm GetFileBytes() chiếm khoảng 20% thời gian (với HDD Thì tỷ lệ % có thể cao hơn)
  2. Hàm ComputeHash_2() ngốn tới 80% thời gian.
Nếu kỹ càng hơn, chúng ta sẽ dùng kết quả từ GetFileBytes() đối chiếu một số byte ở một số ví trị nhất định trong 2 file và độ chính xác sẽ tiệm cận với hàm băm nhưng lại rút ngắn đi gần 80% thời gian thực thi code.
Vâng anh, mọi người đều có ý riêng của mình. Nhưng do tính chất công việc của em thì hiện tại em so sánh luôn cả 2 (vừa băm và size) luôn cho tăng tỉ lệ % cao lên ạ. Hiện tại thì chạy 16.000 ảnh (>2mb ảnh) cũng không quá 5p đâu ạ, còn lâu dài thì chưa biết. :D
 
Upvote 0
Vâng anh, mọi người đều có ý riêng của mình. Nhưng do tính chất công việc của em thì hiện tại em so sánh luôn cả 2 (vừa băm và size) luôn cho tăng tỉ lệ % cao lên ạ. Hiện tại thì chạy 16.000 ảnh (>2mb ảnh) cũng không quá 5p đâu ạ, còn lâu dài thì chưa biết. :D
Nếu bạn suy ngẫm kỹ những ý của tôi thì chắc bạn đã giải quyết việc này vô cùng đơn giản rồi. Với 2 file cùng size, bạn hãy lấy ra 5 byte của mỗi file ở cùng vị trí đối chiếu với nhau thì độ chính xác so sánh cũng gần ngang ngửa dùng hàm băm rồi đấy.

Cụ thể tôi sẽ lấy byte đầu tiên (1), byte thứ 99 (2), byte thứ 999 (3), byte thứ 9999 (4) và byte cuối cùng (5) của mỗi file đem ra đối chiếu. Bạn có thể lấy ra 6, 7, 8... byte - bất cứ số lượng nào đủ lớn ở ví trí rải rác (có thể là 68, 1088...) mà bạn thấy hợp phong thủy --=0 và bạn sẽ khiến chương trình tăng tốc gấp nhiều lần vì vứt bỏ hàm băm nhưng độ chính xác thì không hề thua kém nhé.
 
Upvote 0
Nếu bạn nắm suy ngẫm kỹ những ý của tôi thì chắc bạn đã giải quyết việc này vô cùng đơn giản rồi. Với 2 file cùng size, bạn hãy lấy ra 5 byte của mỗi file ở cùng vị trí đối chiếu với nhau thì độ chính xác so sánh cũng gần ngang ngửa dùng hàm băm rồi đấy.

Cụ thể tôi sẽ lấy byte đầu tiên (1), byte thứ 99 (2), byte thứ 999 (3), byte thứ 9999 (4) và byte cuối cùng (5) của mỗi file đem ra đối chiếu. Bạn có thể lấy ra 6, 7, 8... byte - bất cứ số lượng nào đủ lớn mà bạn thấy hợp phong thủy --=0 và bạn sẽ khiến chương trình tăng tốc gấp nhiều lần vì vứt bỏ hàm băm nhưng độ chính xác thì không hề thua kém nhé.
Hôm trước em có thử so sánh (size) nhưng hình như có bị sót do 2 ảnh trùng nhau nhưng khác (size ở byte thứ 5,6). Để mai em tìm và chạy lại rồi gửi anh xem ạ
 
Upvote 0
Nếu bạn suy ngẫm kỹ những ý của tôi thì chắc bạn đã giải quyết việc này vô cùng đơn giản rồi. Với 2 file cùng size, bạn hãy lấy ra 5 byte của mỗi file ở cùng vị trí đối chiếu với nhau thì độ chính xác so sánh cũng gần ngang ngửa dùng hàm băm rồi đấy.

Cụ thể tôi sẽ lấy byte đầu tiên (1), byte thứ 99 (2), byte thứ 999 (3), byte thứ 9999 (4) và byte cuối cùng (5) của mỗi file đem ra đối chiếu. Bạn có thể lấy ra 6, 7, 8... byte - bất cứ số lượng nào đủ lớn ở ví trí rải rác (có thể là 68, 1088...) mà bạn thấy hợp phong thủy --=0 và bạn sẽ khiến chương trình tăng tốc gấp nhiều lần vì vứt bỏ hàm băm nhưng độ chính xác thì không hề thua kém nhé.
Đợt trước em có chạy theo size thì nó bị như vậy nè anh, nên khả năng lấy theo size không thì cũng không ổn. Vì nếu kiểu này số lượng ảnh càng nhiều thì size trùng em nghĩ nó cũng sẽ nhiều nữa.
Trong 1 thư mục con (>2200 ảnh). Thì sau khi em chạy so sánh theo size thì bị trùng size rất là nhiều (mặc dù 2 ảnh ko ăn nhập gì nhau). Em lấy ra 3 cặp ảnh cho anh xem ạ.
Nhưng sao khi chạy so sánh của cả 2 điều kiện thì không có ảnh nào trùng.
Nên có vẻ cũng khả thi hơn được tí rồi ạ.
Bài đã được tự động gộp:

1649816313458.png
Đợt trước em có chạy theo size thì nó bị như vậy nè anh, nên khả năng lấy theo size không thì cũng không ổn. Vì nếu kiểu này số lượng ảnh càng nhiều thì size trùng em nghĩ nó cũng sẽ nhiều nữa.
Trong 1 thư mục con (>2200 ảnh). Thì sau khi em chạy so sánh theo size thì bị trùng size rất là nhiều (mặc dù 2 ảnh ko ăn nhập gì nhau). Em lấy ra 3 cặp ảnh cho anh xem ạ.
Nhưng sao khi chạy so sánh của cả 2 điều kiện thì không có ảnh nào trùng.
Nên có vẻ cũng khả thi hơn được tí rồi ạ.
 

File đính kèm

  • 1.JPG
    1.JPG
    165.6 KB · Đọc: 11
  • 1+.JPG
    1+.JPG
    155.2 KB · Đọc: 10
  • 2.JPG
    2.JPG
    155.2 KB · Đọc: 9
  • 2+.JPG
    2+.JPG
    148.2 KB · Đọc: 7
  • 3.JPG
    3.JPG
    162.2 KB · Đọc: 7
  • 3+.JPG
    3+.JPG
    146.2 KB · Đọc: 11
Upvote 0
Đợt trước em có chạy theo size thì nó bị như vậy nè anh, nên khả năng lấy theo size không thì cũng không ổn. Vì nếu kiểu này số lượng ảnh càng nhiều thì size trùng em nghĩ nó cũng sẽ nhiều nữa.
Trong 1 thư mục con (>2200 ảnh). Thì sau khi em chạy so sánh theo size thì bị trùng size rất là nhiều (mặc dù 2 ảnh ko ăn nhập gì nhau). Em lấy ra 3 cặp ảnh cho anh xem ạ.
Nhưng sao khi chạy so sánh của cả 2 điều kiện thì không có ảnh nào trùng.
Nên có vẻ cũng khả thi hơn được tí rồi ạ.
Bài đã được tự động gộp:

View attachment 274388
Mình đã test thử lấy 1 bức ảnh copy ra thành 1 bản, chấm 1 chấm nhỏ xíu vào bức ảnh copy, bức ảnh gốc cũng chấm 1 chấm nhỏ xíu khác.
Kết quả là 2 bức ảnh cùng 1 size, chỉ khác nhau có mỗi dấu chấm ở góc. Code vẫn phân biệt rất tốt.
 
Upvote 0
Nếu bạn so sánh size tương đối - nghĩa là có chênh lệch vài byte thì đừng dại so byte cuối nhé.

Một vấn đề nữa là thường lệnh remove/delete file trong VBA sẽ xóa thật sự chứ không phải đưa vô thùng rác nên bắt buộc bạn phải chạy trong một folder được copy. Hoặc để an toàn hơn bạn di chuyển file đoán là trùng lắp vào một folder riêng với tên mới theo nguyên lý [tên file mẫu-tên file cũ.jpg].

Chẳng hạn tôi có file mẫu X.jpg và có file trùng Y.jpg thì tôi copy file X và di chuyển file Y vào thư mục DUP. Lúc này chỉ còn file X trong thư mục chính, trong thư mục DUP sẽ có 2 file là X.jpg và X-Y.jpg. Sau khi hoàn tất chạy code, bạn vô thư mục này để xem lại có bất thường nào xẩy ra không.
 
Lần chỉnh sửa cuối:
Upvote 0
Nếu bạn so sánh size tương đối - nghĩa là có chênh lệch vài byte thì đừng dại so byte cuối nhé.

Một vấn đề nữa là thường lệnh remove/delete file trong VBA sẽ xóa thật sự chứ không phải đưa vô thùng rác nên bắt buộc bạn phải chạy trong một folder được copy. Hoặc để an toàn hơn bạn di chuyển file đoán là trùng lắp vào một folder riêng với tên mới theo nguyên lý [tên file mẫu-tên file cũ.jpg].

Chẳng tôi có file mẫu X.jpg và có file trùng Y.jpg thì tôi copy file X và di chuyển file Y vào thư mục DUP. Lúc này chỉ còn file X trong thư mục chính, trong thư mục DUP sẽ có 2 file là X.jpg và X-Y.jpg. Sau khi hoàn tất chạy code, bạn vô thư mục này để xem lại có bất thường nào xẩy ra không.
Vâng anh, việc này mục đích để em kiểm tra để báo lại thôi ạ chứ không thực hiện xóa ạ. Cảm ơn anh và mọi người nhiều.!
Trân trọng.
 
Upvote 0
Nếu bạn so sánh size tương đối - nghĩa là có chênh lệch vài byte thì đừng dại so byte cuối nhé.

Một vấn đề nữa là thường lệnh remove/delete file trong VBA sẽ xóa thật sự chứ không phải đưa vô thùng rác nên bắt buộc bạn phải chạy trong một folder được copy. Hoặc để an toàn hơn bạn di chuyển file đoán là trùng lắp vào một folder riêng với tên mới theo nguyên lý [tên file mẫu-tên file cũ.jpg].

Chẳng tôi có file mẫu X.jpg và có file trùng Y.jpg thì tôi copy file X và di chuyển file Y vào thư mục DUP. Lúc này chỉ còn file X trong thư mục chính, trong thư mục DUP sẽ có 2 file là X.jpg và X-Y.jpg. Sau khi hoàn tất chạy code, bạn vô thư mục này để xem lại có bất thường nào xẩy ra không.
Ý của anh rất hay và phù hợp. :sun:
Em chỉ có thể chạy thêm 1 đoạn code đơn giản để xóa đi những bức ảnh trùng mà không thể kiểm tra hết được liệu các ảnh đó có quan trọng hay không.
Việc đưa hết vào chung 1 thư mục sẽ tiện cho việc quản lý hơn, dữ liệu cũng an toàn hơn.
Anh có thể code phát triển giúp thêm được không ạ.
Nhờ chủ đề này của chủ thớt và các ACE GPE giúp mà em đã dọn dẹp được 1 mớ ảnh rác từ hồi chục năm đổ lại tới giờ, lúc trước file lưu trong thẻ nhớ bị virus ảnh nó tự nhân lên quá trời.
 
Upvote 0
Chủ đề này có vẻ nóng. 6 trang rồi mà chưa thấy có điểm dừng --=0
 
Upvote 0

Đây nhé bạn nhé .

 
Upvote 0
Chủ thớt lại phải nhọc công viết code mở file log, tìm file trùng theo đường dẫn trong đó để xóa.
 
Upvote 0
Web KT
Back
Top Bottom