Phát hiện trên sông


175

Trong phần trao đổi TeX, chúng tôi đã thảo luận về cách phát hiện "các dòng sông" trong các đoạn trong câu hỏi này .

Trong bối cảnh này, các dòng sông là các dải không gian màu trắng xuất phát từ sự liên kết ngẫu nhiên của các không gian từ trong văn bản. Vì điều này có thể gây mất tập trung cho người đọc, những dòng sông xấu được coi là một triệu chứng của kiểu chữ kém. Một ví dụ về văn bản với các con sông là cái này, nơi có hai con sông chảy theo đường chéo.

nhập mô tả hình ảnh ở đây

Có mối quan tâm trong việc phát hiện các con sông này một cách tự động, để chúng có thể tránh được (có thể bằng cách chỉnh sửa thủ công văn bản). Raphink đang đạt được một số tiến bộ ở cấp độ TeX (chỉ biết về vị trí glyph và hộp giới hạn), nhưng tôi cảm thấy tự tin rằng cách tốt nhất để phát hiện các dòng sông là xử lý hình ảnh (vì hình dạng glyph rất quan trọng và không có sẵn cho TeX) . Tôi đã thử nhiều cách khác nhau để trích xuất các dòng sông từ hình ảnh trên, nhưng ý tưởng đơn giản của tôi về việc áp dụng một lượng nhỏ làm mờ hình elip dường như không đủ tốt. Tôi cũng đã thử một số RadonLọc dựa trên biến đổi Hough, nhưng tôi cũng không nhận được bất cứ nơi nào với những cái đó. Các con sông rất dễ thấy các mạch phát hiện tính năng của mắt / võng mạc / não người và bằng cách nào đó tôi nghĩ rằng nó có thể được dịch sang một loại hoạt động lọc nào đó, nhưng tôi không thể làm cho nó hoạt động. Có ý kiến ​​gì không?

Cụ thể, tôi đang tìm kiếm một số hoạt động sẽ phát hiện 2 con sông trong hình trên, nhưng không có quá nhiều phát hiện dương tính giả khác.

EDIT: endolith đã hỏi tại sao tôi theo đuổi cách tiếp cận dựa trên xử lý hình ảnh cho rằng trong TeX chúng tôi có quyền truy cập vào các vị trí glyph, khoảng cách, v.v. và có thể sử dụng thuật toán kiểm tra văn bản thực tế nhanh hơn và đáng tin cậy hơn nhiều. Lý do của tôi để làm mọi thứ theo cách khác là hình dạngcủa glyphs có thể ảnh hưởng đến mức độ đáng chú ý của một dòng sông, và ở cấp độ văn bản, rất khó để xem xét hình dạng này (điều này phụ thuộc vào phông chữ, vào ligaturing, v.v.). Để biết ví dụ về cách hình dạng của glyphs có thể quan trọng, hãy xem xét hai ví dụ sau, trong đó điểm khác biệt giữa chúng là tôi đã thay thế một vài glyphs bằng các glyphs khác có cùng chiều rộng, để phân tích dựa trên văn bản sẽ xem xét họ tốt / xấu như nhau. Tuy nhiên, lưu ý rằng các con sông trong ví dụ đầu tiên tồi tệ hơn nhiều so với trong lần thứ hai.

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây


5
+1 Tôi thích câu hỏi này. Suy nghĩ đầu tiên của tôi là Hough Transform , nhưng có lẽ nó sẽ cần một số tiền xử lý. Có thể là một bộ lọc giãn nở đầu tiên.
datageist

Tôi thực sự ngạc nhiên khi biến đổi Radon không hoạt động. Bạn đã làm nó như thế nào?
endolith

@endolith: Không có gì tinh vi. Tôi đã sử dụng ImageLines[]từ Mathicala, có và không có một số tiền xử lý. Tôi đoán đây là kỹ thuật sử dụng biến đổi Hough chứ không phải Radon. Tôi sẽ không ngạc nhiên nếu quá trình tiền xử lý thích hợp (Tôi đã không thử bộ lọc giãn nở được đề xuất của datageist) và / hoặc cài đặt tham số có thể làm cho công việc này hoạt động.
Lev Giám mục

Google Image Search cho các dòng sông cũng cho thấy các dòng sông "quanh co". Bạn có muốn tìm những thứ đó không? cdn.ilovetypography.com/img/text-river1.gif
endolith

@endolith Tôi đoán cuối cùng tôi muốn sao chép quá trình xử lý hệ thống thị giác của con người khiến cho các cấu hình nhất định của không gian bị phân tâm. Vì điều này cũng có thể xảy ra đối với các con sông uốn khúc, nên tôi muốn bắt những con sông đó, mặc dù những con thẳng có vẻ là một vấn đề nói chung. Thậm chí tốt hơn sẽ là một cách để định lượng "tính xấu" của các con sông theo cách tương ứng với mức độ chúng có thể nhìn thấy mạnh mẽ khi đọc văn bản. Nhưng đó là tất cả rất chủ quan và khó định lượng. Ở nơi đầu tiên, chỉ cần bắt thực sự tất cả các dòng sông xấu mà không có quá nhiều tích cực sai sẽ làm.
Lev Giám mục

Câu trả lời:


135

Tôi đã nghĩ về điều này nhiều hơn nữa, và nghĩ rằng những điều sau đây nên khá ổn định. Lưu ý rằng tôi đã giới hạn bản thân mình cho các hoạt động hình thái, bởi vì chúng nên có sẵn trong bất kỳ thư viện xử lý hình ảnh tiêu chuẩn nào.

(1) Mở hình ảnh với mặt nạ nPix-by-1, trong đó nPix là khoảng cách dọc giữa các chữ cái

#% read image
img = rgb2gray('http://i.stack.imgur.com/4ShOW.png');

%# threshold and open with a rectangle
%# that is roughly letter sized
bwImg = img > 200; %# threshold of 200 is better than 128

opImg = imopen(bwImg,ones(13,1));

nhập mô tả hình ảnh ở đây

(2) Mở hình ảnh với mặt nạ 1-mPix để loại bỏ bất cứ thứ gì quá hẹp để trở thành một dòng sông.

opImg = imopen(opImg,ones(1,5));

nhập mô tả hình ảnh ở đây

(3) Loại bỏ "sông hồ" nằm ngang do không gian giữa các đoạn hoặc thụt lề. Đối với điều này, chúng tôi xóa tất cả các hàng hoàn toàn đúng và mở bằng mặt nạ nPix-by-1 mà chúng tôi biết sẽ không ảnh hưởng đến các dòng sông mà chúng tôi đã tìm thấy trước đây.

Để loại bỏ các hồ, chúng ta có thể sử dụng mặt nạ mở lớn hơn một chút so với nPix-by-nPix.

Ở bước này, chúng ta cũng có thể loại bỏ mọi thứ quá nhỏ để trở thành một dòng sông thực sự, tức là mọi thứ có diện tích nhỏ hơn (nPix + 2) * (mPix + 2) * 4 (sẽ cho chúng ta ~ 3 dòng). +2 ở đó bởi vì chúng ta biết rằng tất cả các đối tượng đều có chiều cao ít nhất là nPix và chiều rộng mPix và chúng ta muốn vượt lên trên một chút.

%# horizontal river: just look for rows that are all true
opImg(all(opImg,2),:) = false;
%# open with line spacing (nPix)
opImg = imopen(opImg,ones(13,1));

%# remove lakes with nPix+2
opImg = opImg & ~imopen(opImg,ones(15,15)); 

%# remove small fry
opImg = bwareaopen(opImg,7*15*4);

nhập mô tả hình ảnh ở đây

(4) Nếu chúng ta quan tâm không chỉ chiều dài, mà cả chiều rộng của dòng sông, chúng ta có thể kết hợp biến đổi khoảng cách với bộ xương.

   dt = bwdist(~opImg);
   sk = bwmorph(opImg,'skel',inf);
   %# prune the skeleton a bit to remove branches
   sk = bwmorph(sk,'spur',7);

   riversWithWidth = dt.*sk;

nhập mô tả hình ảnh ở đây (màu sắc tương ứng với chiều rộng của dòng sông (mặc dù thanh màu bị tắt theo hệ số 2)

Bây giờ bạn có thể lấy chiều dài gần đúng của các con sông bằng cách đếm số pixel trong mỗi thành phần được kết nối và chiều rộng trung bình bằng cách lấy trung bình các giá trị pixel của chúng.


Đây là phân tích chính xác được áp dụng cho hình ảnh "không có sông" thứ hai:

nhập mô tả hình ảnh ở đây


Cảm ơn. Tôi có Matlab vì vậy tôi sẽ thử điều này trên một số văn bản khác để xem nó sẽ mạnh đến mức nào.
Lev Giám mục

Để tích hợp nó trở lại vào TeX có thể là một vấn đề khác, trừ khi chúng ta có thể chuyển nó sang Lua bằng cách nào đó.
ℝaphink

@LevBishop: Tôi nghĩ rằng tôi hiểu vấn đề tốt hơn một chút. Các giải pháp mới nên khá mạnh mẽ.
Jonas

@levBishop: Thêm một bản cập nhật.
Jonas

1
@LevBishop: Chỉ cần chú ý hình ảnh thứ hai. Hóa ra phân tích dựa trên hình thái làm công việc của nó.
Jonas

56

Trong Mathicala, sử dụng biến đổi xói mòn và biến đổi Hough:

(*Get Your Images*)
i = Import /@ {"http://i.stack.imgur.com/4ShOW.png", 
               "http://i.stack.imgur.com/5UQwb.png"};

(*Erode and binarize*)
i1 = Binarize /@ (Erosion[#, 2] & /@ i);

(*Hough transform*)
lines = ImageLines[#, .5, "Segmented" -> True] & /@ i1;

(*Ready, show them*)
Show[#[[1]],Graphics[{Thick,Orange, Line /@ #[[2]]}]] & /@ Transpose[{i, lines}]

nhập mô tả hình ảnh ở đây

Chỉnh sửa Trả lời bình luận của ông Wizard

Nếu bạn muốn thoát khỏi các đường ngang, chỉ cần làm một cái gì đó như thế này (có lẽ ai đó có thể làm cho nó đơn giản hơn):

Show[#[[1]], Graphics[{Thick, Orange, Line /@ #[[2]]}]] & /@ 
 Transpose[{i, Select[Flatten[#, 1], Chop@Last@(Subtract @@ #) != 0 &] & /@ lines}]

nhập mô tả hình ảnh ở đây


1
Tại sao không thoát khỏi tất cả các đường ngang? (+1)
Mr.Wizard

@Ông. Chỉ để hiển thị tất cả các dòng đang được phát hiện ...
Tiến sĩ belisarius

1
Đó không phải là một phần của vấn đề, phải không?
Mr.Wizard

@Ông. Chỉnh sửa theo yêu cầu
Tiến sĩ belisarius

4
@belisarius Hệ tọa độ được sử dụng trong biến đổi Hough đã thay đổi sau 8.0.0 để khớp với biến đổi Radon. Chính điều này đã thay đổi hành vi của ImageLines. Nhìn chung đây là một sự cải tiến, mặc dù trong trường hợp này, người ta sẽ thích hành vi trước đó. Nếu bạn không muốn thử nghiệm với các phát hiện cao điểm, bạn có thể thay đổi tỷ lệ khung hình của hình ảnh đầu vào để gần hơn 1 và có được kết quả tương tự như 8.0.0 : lines = ImageLines[ImageResize[#, {300, 300}], .6, "Segmented" -> True] & /@ i1;. Tất cả những gì đang được nói, đối với vấn đề này, một cách tiếp cận hình thái có vẻ mạnh mẽ hơn.
Matthias Odisio

29

Hmmm ... tôi đoán biến đổi Radon không dễ dàng trích xuất từ ​​đó. (Biến đổi radon về cơ bản làm xoay hình ảnh trong khi "nhìn xuyên qua nó". Đó là nguyên tắc đằng sau quét CAT.) Biến đổi hình ảnh của bạn tạo ra hình sin này, với các "dòng sông" tạo thành các đỉnh sáng, được khoanh tròn:

nhập mô tả hình ảnh ở đây

Một góc quay 70 độ có thể được nhìn thấy khá rõ là đỉnh bên trái của ô này của một lát cắt dọc theo trục ngang:

nhập mô tả hình ảnh ở đây

Đặc biệt nếu văn bản bị Gaussian làm mờ trước:

nhập mô tả hình ảnh ở đây

Nhưng tôi không chắc làm thế nào để trích xuất các đỉnh này một cách đáng tin cậy từ phần còn lại của tiếng ồn. Phần trên cùng và dưới cùng của hình sin đại diện cho "dòng sông" giữa các dòng văn bản nằm ngang mà bạn rõ ràng không quan tâm. Có lẽ một hàm trọng số so với góc làm nổi bật các đường thẳng đứng hơn và giảm thiểu các đường ngang?

Một chức năng cân cosine đơn giản hoạt động tốt trên hình ảnh này:

nhập mô tả hình ảnh ở đây

tìm dòng sông thẳng đứng ở góc 90 độ, đó là cực đại toàn cầu trong hình sin:

nhập mô tả hình ảnh ở đây

và trên hình ảnh này, việc tìm kiếm một góc ở 104 độ, mặc dù việc làm mờ trước làm cho nó chính xác hơn:

nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây

( radon()Chức năng của SciPy là một sự ngớ ngẩn , hoặc tôi sẽ ánh xạ đỉnh này trở lại hình ảnh ban đầu khi một dòng đi qua giữa dòng sông.)

Nhưng nó không tìm thấy một trong hai đỉnh chính trong hình sin cho hình ảnh của bạn, sau khi làm mờ và cân:

nhập mô tả hình ảnh ở đây

Họ ở đó, nhưng họ bị choáng ngợp bởi những thứ gần đỉnh cao nhất của hàm trọng số. Với trọng số phù hợp và điều chỉnh phương pháp này có thể có thể hoạt động, nhưng tôi không chắc những điều chỉnh đúng là gì. Nó có thể phụ thuộc vào các thuộc tính của quét của trang, quá. Có lẽ trọng số cần phải được lấy từ năng lượng tổng thể trong lát cắt hoặc một cái gì đó, giống như một chuẩn hóa.

from pylab import *
from scipy.misc import radon
import Image

filename = 'rivers.png'
I = asarray(Image.open(filename).convert('L').rotate(90))

# Do the radon transform and display the result
a = radon(I, theta = mgrid[0:180])

# Remove offset
a = a - min(a.flat)

# Weight it to emphasize vertical lines
b = arange(shape(a)[1]) #
d = (0.5-0.5*cos(b*pi/90))*a

figure()
imshow(d.T)
gray()
show()

# Find the global maximum, plot it, print it
peak_x, peak_y = unravel_index(argmax(d),shape(d))
plot(peak_x, peak_y,'ro')
print len(d)- peak_x, 'pixels', peak_y, 'degrees'

Điều gì nếu bạn làm mờ với một Gaussian bất đối xứng đầu tiên? Tức là hẹp theo hướng ngang, rộng theo hướng dọc.
Jonas

@Jonas: Điều đó có thể sẽ giúp. Vấn đề chính là tự động chọn các đỉnh ra khỏi nền khi nền thay đổi rất nhiều với xoay vòng. Làm mờ không đối xứng có thể làm nhẵn các sọc ngang từ dòng này sang dòng khác.
endolith

Điều này hoạt động tốt để phát hiện sự xoay vòng của các dòng trong văn bản, ít nhất là: gist.github.com/endolith/334196bac1cac45a4893
endolith

16

Tôi đã đào tạo một trình phân loại phân biệt đối xử trên các pixel bằng cách sử dụng các tính năng phái sinh (lên đến bậc 2) trên các thang đo khác nhau.

Nhãn của tôi:

Dán nhãn

Dự đoán về hình ảnh đào tạo:

nhập mô tả hình ảnh ở đây

Dự đoán về hai hình ảnh khác:

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

Tôi đoán điều này có vẻ đầy hứa hẹn và có thể mang lại kết quả có thể sử dụng được với nhiều dữ liệu đào tạo hơn và có thể các tính năng thông minh hơn. Mặt khác, tôi chỉ mất vài phút để có được những kết quả này. Bạn có thể tự tái tạo kết quả bằng cách sử dụng phần mềm nguồn mở ilastik . [Tuyên bố miễn trừ trách nhiệm: Tôi là một trong những nhà phát triển chính.]


2

(Xin lỗi, bài đăng này không đi kèm với các cuộc biểu tình tuyệt vời.)

Nếu bạn muốn làm việc với thông tin TeX đã có (chữ cái và vị trí), bạn có thể phân loại thủ công các chữ cái và cặp chữ cái là "dốc" theo hướng này hay hướng khác. Ví dụ: "w" có độ dốc góc SW và SE, tổ hợp "al" có độ dốc góc NW, "k" có độ dốc góc NE. (Đừng quên dấu câu - một trích dẫn theo sau là một chữ cái lấp đầy nửa dưới của hộp glyph tạo ra độ dốc đẹp; trích dẫn theo sau là q đặc biệt mạnh.)

Sau đó, tìm kiếm sự xuất hiện của các sườn tương ứng ở các phía đối diện của một không gian - "w al" cho một dòng sông SW-to-NE hoặc "k T" cho một dòng sông từ NA đến SE. Khi bạn tìm thấy một dòng trên một dòng, hãy xem nếu một cái tương tự xảy ra, dịch chuyển sang trái hoặc phải một cách thích hợp, trên các dòng trên / dưới; Khi bạn tìm thấy một loạt những thứ này, có lẽ có một dòng sông.

Ngoài ra, rõ ràng, chỉ cần tìm các không gian xếp chồng lên nhau gần như theo chiều dọc, cho các dòng sông thẳng đứng.

Bạn có thể tinh vi hơn một chút bằng cách đo "cường độ" của độ dốc: bao nhiêu hộp trước là "trống" do độ dốc và do đó đóng góp vào chiều rộng của dòng sông. "W" khá nhỏ, vì nó chỉ có một góc nhỏ trong hộp trước để đóng góp cho dòng sông, nhưng "V" rất mạnh. "b" mạnh hơn một chút so với "k"; đường cong nhẹ nhàng hơn cho cạnh sông liên tục hơn, làm cho nó mạnh hơn và rộng hơn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.