การค้นหาลวดลายเหมือนม้าลายในภาพ (การตรวจจับกึ่งกลางขอบแสงแบบมีโครงสร้างจากภาพถ่าย)


12

ฉันกำลังทำงานในโครงการที่มีการฉายบริเวณขอบภาพกับเรื่องและถ่ายภาพ ภารกิจคือการหาเส้นกลางของขอบซึ่งเป็นตัวแทนทางคณิตศาสตร์, เส้นโค้ง 3 มิติของการแยกระหว่างระนาบขอบและพื้นผิวของเรื่อง

ภาพถ่ายเป็น PNG (RGB) และความพยายามในอดีตเคยใช้การไล่ระดับสีเทาจากนั้นจึงปรับความแตกต่างของภาพเพื่อให้ได้ภาพถ่ายขาวดำที่มีลักษณะคล้ายม้าลายซึ่งง่ายต่อการค้นหาจุดกึ่งกลางของแต่ละพิกเซลของแต่ละขอบ ปัญหาคือโดยการกำหนดค่าใหม่และด้วยการใช้ความสูงเฉลี่ยของคอลัมน์พิกเซลแยกเรามีการสูญเสียและความแม่นยำเชิงปริมาณบางอย่างซึ่งไม่ต้องการเลย

ความประทับใจของฉันจากการดูภาพคือเส้นกลางอาจต่อเนื่องได้มากกว่า (มีจุดมากขึ้น) และนุ่มนวลขึ้น (ไม่นับจำนวน) หากตรวจพบได้โดยตรงจากภาพที่ไม่ผ่านเกณฑ์ (เช่น RGB หรือโทนสีเทา) โดยวิธีการทางสถิติ (น้ำท่วม / วนซ้ำวนซ้ำอะไรก็ตาม)

ด้านล่างเป็นภาพตัวอย่างจริง:

ป้อนคำอธิบายรูปภาพที่นี่

ข้อเสนอแนะใด ๆ ที่จะได้รับการชื่นชมมาก!


มันน่าสนใจอย่างมาก. แต่อย่างไรก็ตามฉันกำลังทำวิจัยโดยใช้แถบสีเพื่อตรวจจับวัตถุ 3 มิติ เนื่องจากการใช้แถบสีจึงเป็นเรื่องง่ายในการค้นหาความสอดคล้องของแต่ละแถบจากโปรเจ็กเตอร์ดังนั้นการใช้ตรีโกณมิติทำให้สามารถคำนวณข้อมูล 3 มิติได้ คุณจะพบความสอดคล้องกันได้อย่างไรถ้าสีเหมือนกัน? ฉันเดาว่าโครงการของคุณเกี่ยวกับการสร้างแบบ 3 มิติอีกหรือไม่

@johnyoung: โปรดอย่าเพิ่มความคิดเห็นเป็นคำตอบ ฉันรู้ว่าคุณต้องการชื่อเสียงก่อนที่คุณจะสามารถแสดงความคิดเห็นได้ แต่โปรดงดเว้นจากการกระทำในปัจจุบันของคุณ ฉันขอแนะนำให้ถามคำถามของคุณเอง (ที่เกี่ยวข้อง) หรือตอบคำถามของผู้อื่นเพื่อเพิ่มตัวแทนของคุณ
Peter K.

ขออภัยสำหรับคำถามอีกหนึ่งคำถามแทนที่จะให้คำตอบในวิธีการเปลี่ยนเฟสเราคำนวณเฟสที่แต่ละพิกเซลในภาพที่ฉาย แต่ที่นี่ทำไมเราต้องค้นหาเส้นกึ่งกลางของขอบอาจเป็นคำถามของฉันคือโง่มาก แต่ฉันไม่ ไม่ได้ดังนั้นโปรดโทรหาฉันด้วยเหตุผลที่แน่นอน คุณสามารถลบคำถามของฉันหลังจากที่ให้คำตอบ

เหล่านี้เป็นวิธีการที่แตกต่างกัน ฉันกำลังสร้างโมเดลเครื่องบินเรขาคณิตโดยฉายแถบสีขาวหลายชุด (แต่ละอันสร้าง "ระนาบ" ในอวกาศ 3 มิติ) ดังนั้นฉันต้องหาเส้นกึ่งกลางของขอบเพราะเครื่องบินไม่มีความหนา แน่ใจว่าฉันสามารถทำการวิเคราะห์การเปลี่ยนเฟส แต่มีปัญหาหนึ่ง: การฉายภาพของฉันเป็นแบบไบนารี่ (แถบสีดำและสีขาวสลับกัน) ความเข้มไม่แตกต่างกันไปตามไซน์ดังนั้นฉันจึงไม่สามารถทำการขยับเฟสได้ )
heltonbiker

คำตอบ:


13

ฉันขอแนะนำขั้นตอนต่อไปนี้:

  1. ค้นหาขีด จำกัด เพื่อแยกพื้นหน้าออกจากพื้นหลัง
  2. สำหรับแต่ละหยดในภาพไบนารี (หนึ่งแถบม้าลาย) สำหรับแต่ละจุดxให้หาจุดศูนย์กลางถ่วงน้ำหนัก (ตามความเข้มของพิกเซล) ในyทิศทาง
  3. อาจจะปรับyค่าให้เรียบเพื่อขจัดเสียงรบกวน
  4. เชื่อมต่อ(x,y)จุดต่าง ๆ ด้วยการเข้าโค้งบางอย่าง บทความนี้อาจช่วยคุณได้ คุณยังสามารถใส่พหุนามระดับสูงได้ในความคิดของฉัน

นี่คือรหัส Matlab ที่แสดงขั้นตอนที่ 1,2 และ 4 ฉันข้ามการเลือกเกณฑ์อัตโนมัติ ฉันเลือกคู่มือแทนth=40:

นี่คือเส้นโค้งที่พบโดยการหาค่าเฉลี่ยถ่วงน้ำหนักต่อคอลัมน์: ป้อนคำอธิบายรูปภาพที่นี่

นี่คือส่วนโค้งหลังจากใส่พหุนามเข้าด้วยกัน: ป้อนคำอธิบายรูปภาพที่นี่

นี่คือรหัส:

function Zebra()
    im = imread('http://i.stack.imgur.com/m0sy7.png');
    im = uint8(mean(im,3));

    th = 40;
    imBinary = im>th;
    imBinary = imclose(imBinary,strel('disk',2));
    % figure;imshow(imBinary);
    labels = logical(imBinary);
    props =regionprops(labels,im,'Image','Area','BoundingBox');

    figure(1);imshow(im .* uint8(imBinary));
    figure(2);imshow(im .* uint8(imBinary));

    for i=1:numel(props)
        %Ignore small ones
        if props(i).Area < 10
            continue
        end
        %Find weighted centroids
        boundingBox = props(i).BoundingBox;
        ul = boundingBox(1:2)+0.5;
        wh = boundingBox(3:4);
        clipped = im( ul(2): (ul(2)+wh(2)-1), ul(1): (ul(1)+wh(1)-1) );
        imClip = double(props(i).Image) .* double(clipped);
        rows = transpose( 1:size(imClip,1) );
        %Weighted calculation
        weightedRows  = sum(bsxfun(@times, imClip, rows),1) ./ sum(imClip,1);
        %Calculate x,y
        x = ( 1:numel(weightedRows) ) + ul(1) - 1;
        y = ( weightedRows ) + ul(2) - 1;
        figure(1);
        hold on;plot(x,y,'b','LineWidth',2);
        try %#ok<TRYNC>
            figure(2);
            [xo,yo] = FitCurveByPolynom(x,y);
            hold on;plot(xo,yo,'g','LineWidth',2);
        end
        linkaxes( cell2mat(get(get(0,'Children'),'Children')) )
    end        
end

function [xo,yo] = FitCurveByPolynom(x,y)
   p = polyfit(x,y,15); 
   yo = polyval(p,x);
   xo = x;
end

ฉันพบสิ่งนี้น่าสนใจมาก ฉันใช้ Python แต่ฉันจะต้องศึกษาเหตุผลทั้งหมดนี้ ในฐานะที่เป็นความคิดเห็นอิสระฉันมักจะไม่ทำการประมวลผลภาพคลาสสิก (โดยตรงกับภาชนะบรรจุภาพเชิงปริมาณเช่นอาร์เรย์ uint8) แต่โหลดทุกอย่างไปยังหน่วยความจำเป็นอาร์เรย์ลอยก่อนที่จะใช้การดำเนินการ นอกจากนี้ฉันยังประหลาดใจกับผลลัพธ์ที่ได้จากครึ่งล่างของภาพของคุณเส้นสีน้ำเงินไม่ได้วิ่งไปตามกึ่งกลางขอบที่คาดหวัง ... (?) ขอบคุณสำหรับตอนนี้ฉันจะให้ข้อเสนอแนะบางอย่างทันทีที่ฉันได้รับผล!
heltonbiker

@heltonbiker โปรดตรวจสอบคำตอบที่ปรับปรุงแล้ว doubleคุณจะต้องเกี่ยวกับจุดลอยผมใช้มันเมื่อฉันแปลง เกี่ยวกับผลลัพธ์ในครึ่งล่างฉันต้องตรวจสอบว่าอาจเป็นข้อผิดพลาดของซอฟต์แวร์
Andrey Rubshtein

1
@heltonbiker เสร็จแล้ว มันเป็นข้อผิดพลาดที่เกี่ยวข้องกับการจัดทำดัชนีตาม 1 อย่างแน่นอน
Andrey Rubshtein

Excelent! น่าทึ่งมาก ด้วยเทคนิคนี้และเพื่อจุดประสงค์ของฉันการปรับให้เรียบไม่เพียง แต่ไม่จำเป็นเท่านั้น แต่ยังเป็นอันตรายด้วย ขอบคุณมากสำหรับความสนใจของคุณ!
heltonbiker

3

ฉันจะไม่ใช้ภาพ RGB โดยทั่วไปแล้วจะมีการสร้างภาพสีโดยใส่"ตัวกรองไบเออร์"ลงในเซ็นเซอร์กล้องซึ่งโดยปกติจะลดความละเอียดที่คุณสามารถทำได้

หากคุณใช้ภาพระดับสีเทาฉันคิดว่าขั้นตอนที่คุณอธิบายไว้ (ภาพ "ม้าลาย", ค้นหากึ่งกลาง) เป็นการเริ่มต้นที่ดี เป็นขั้นตอนสุดท้ายฉันจะ

  • ใช้แต่ละจุดในกึ่งกลางที่คุณพบ
  • ใช้ค่าเทาในพิกเซลในบรรทัด "ม้าลาย" ด้านบนและด้านล่าง
  • พอดีพาราโบลากับค่าเทาเหล่านี้โดยใช้กำลังสองน้อยที่สุด
  • จุดยอดของพาราโบลานี้เป็นการประเมินตำแหน่ง midline ที่ดีขึ้น

ความคิดที่ดี ฉันวางแผนที่จะใช้พาราโบลาหรือเส้นโค้งบางอย่างตามค่าสูงสุดของแต่ละคอลัมน์พิกเซล แต่ฉันยังคงสงสัยว่าฉันควรตรวจสอบคอลัมน์พิกเซลหรือไม่หรือแทนที่จะใช้พิกเซล "ภูมิภาค" ตามเส้น ... จะรออีก คำตอบเพิ่มเติม ขอบคุณสำหรับตอนนี้!
heltonbiker

@heltonbiker - เป็นการทดสอบที่รวดเร็วใช้เฉพาะช่องสีเขียว โดยปกติจะมีพิกเซลสีเขียวมากถึง 2 เท่าบนเซ็นเซอร์สีและมีค่าน้อยกว่าสีแดงและสีน้ำเงิน
Martin Beckett

@MartinBeckett ขอบคุณสำหรับความสนใจของคุณฉันได้วิเคราะห์แต่ละช่องแล้วและแน่นอนช่องสีเขียวดูเหมือนจะได้รับการแก้ไขมากกว่าพูดช่องสีแดง การพล็อตค่าความเข้มของส่วนตัดขวางแนวตั้งสำหรับแต่ละแชแนลแม้ว่า "รูปแบบสไทรพ์" ดูเหมือนจะไม่เปลี่ยนแปลงมากนักระหว่างแชนเนล แม้ว่าฉันจะยังคงวางแผนที่จะศึกษาชุดค่าผสมเชิงเส้นที่ดีที่สุดระหว่างแชนเนลเพื่อให้ได้ผลลัพธ์ที่ดีที่สุดหรือเพื่อให้ได้ภาพที่เป็นสีเทา ขอบคุณอีกครั้ง!
heltonbiker

3

นี่คือวิธีการแก้ปัญหาทางเลือกของคุณโดยการสร้างแบบจำลองคำถามของคุณเป็น 'ปัญหาการเพิ่มประสิทธิภาพเส้นทาง' ถึงแม้ว่ามันจะซับซ้อนกว่าโซลูชันแบบไบนาไนเซชันและเส้นโค้งแบบง่าย ๆ แต่ก็มีความแข็งแกร่งในทางปฏิบัติ

จากระดับที่สูงมากเราควรพิจารณาภาพนี้เป็นกราฟ

  1. แต่ละพิกเซลของรูปภาพเป็นโหนดบนกราฟนี้

  2. แต่ละโหนดเชื่อมต่อกับโหนดอื่น ๆ ที่รู้จักกันในชื่อเพื่อนบ้านและคำจำกัดความการเชื่อมต่อนี้มักจะเรียกว่าโทโพโลยีของกราฟนี้

  3. แต่ละโหนดมีน้ำหนัก (คุณสมบัติราคาพลังงานหรืออะไรก็ตามที่คุณต้องการเรียก) เพื่อสะท้อนถึงความเป็นไปได้ที่โหนดนี้อยู่ในสายกลางที่ดีที่สุดที่เรากำลังมองหา

ตราบใดที่เราสามารถสร้างแบบจำลองโอกาสนี้แล้วปัญหาของคุณในการค้นหา 'เส้นกลางของขอบ' กลายเป็นปัญหาเพื่อค้นหาเส้นทางที่เหมาะสมที่สุดในท้องถิ่นบนกราฟซึ่งสามารถแก้ไขได้อย่างมีประสิทธิภาพโดยการโปรแกรมแบบไดนามิกเช่นอัลกอริทึม Viterbi

นี่คือข้อดีของการใช้วิธีนี้:

  1. ผลลัพธ์ทั้งหมดของคุณจะต่อเนื่อง (ซึ่งแตกต่างจากวิธีเกณฑ์ที่อาจแบ่งหนึ่งบรรทัดกลางเป็นชิ้น ๆ )

  2. เสรีภาพมากมายในการสร้างกราฟเช่นนี้คุณสามารถเลือกคุณสมบัติที่แตกต่างกันและทอพอโลยีกราฟ

  3. ผลลัพธ์ของคุณดีที่สุดในแง่ของการปรับเส้นทางให้เหมาะสม

  4. โซลูชันของคุณจะทนทานต่อเสียงรบกวนได้มากขึ้นเพราะตราบใดที่เสียงรบกวนนั้นมีการกระจายอย่างเท่าเทียมกันในทุกพิกเซลเส้นทางที่เหมาะสมเหล่านั้นยังคงมีเสถียรภาพ

นี่คือการสาธิตสั้น ๆ ของความคิดข้างต้น เนื่องจากฉันไม่ใช้ความรู้ก่อนหน้าใด ๆ เพื่อระบุสิ่งที่เป็นไปได้เริ่มต้นและสิ้นสุดโหนดฉันก็ถอดรหัส wrt ทุกโหนดเริ่มต้นที่เป็นไปได้ เส้นทาง Viterbi ที่ถอดรหัส

สำหรับตอนจบที่เลือนมันเกิดจากความจริงที่ว่าเรากำลังมองหาเส้นทางที่ดีที่สุดสำหรับทุกโหนดสิ้นสุดที่เป็นไปได้ เป็นผลให้สำหรับบางโหนดที่อยู่ในพื้นที่มืดพา ธ ที่ไฮไลต์ยังคงเป็นโหนดที่ดีที่สุดในพื้นที่

สำหรับเส้นทางที่คลุมเครือคุณสามารถปรับให้เรียบหลังจากค้นหาหรือใช้คุณสมบัติที่ปรับให้เรียบแทนที่จะใช้ความเข้มแบบดิบ

เป็นไปได้ที่จะกู้คืนพา ธ บางส่วนโดยเปลี่ยนโหนดเริ่มต้นและสิ้นสุด

มันจะไม่ยากที่จะตัดเส้นทางที่ดีที่สุดในท้องถิ่นที่ไม่พึงประสงค์เหล่านี้ เนื่องจากเรามีความเป็นไปได้ของทุกเส้นทางหลังจากการถอดรหัส viterbi และคุณอาจใช้ความรู้เดิม ๆ (เช่นเราเห็นว่าเป็นความจริงที่ว่าเราต้องการเส้นทางที่ดีที่สุดเพียงเส้นทางเดียวสำหรับผู้ที่แบ่งปันแหล่งเดียวกัน)

สำหรับรายละเอียดเพิ่มเติมคุณอาจอ้างถึงกระดาษ

 Wu, Y.; Zha, S.; Cao, H.; Liu, D., & Natarajan, P.  (2014, February). A Markov Chain Line Segmentation Method for Text Recognition. In IS&T/SPIE 26th Annual Symposium on Electronic Imaging (DRR), pp. 90210C-90210C.

นี่คือส่วนหนึ่งของรหัสหลามที่ใช้สร้างกราฟด้านบน


import cv2
import numpy as np
from matplotlib import pyplot
# define your image path
image_path = ;
# read in an image
img = cv2.imread( image_path, 0 );
rgb = cv2.imread( image_path, -1 );

# some feature to reflect how likely a node is in an optimal path
img = cv2.equalizeHist( img ); # equalization
img = img - img.mean(); # substract DC
img_pmax = img.max(); # get brightest intensity
img_nmin = img.min(); # get darkest intensity
# express our preknowledge
img[ img > 0 ] *= +1.0  / img_pmax; 
img[ img = 1 :
    prev_idx = vt_path[ -1 ].astype('int');
    vt_path.append( path_buffer[ prev_idx, time ] );
    time -= 1;
vt_path.reverse();    
vt_path = np.asarray( vt_path ).T;

# plot found optimal paths for every 7 of them
pyplot.imshow( rgb, 'jet' ),
for row in range( 0, h, 7 ) :
    pyplot.hold(True), pyplot.plot( vt_path[row,:], c=np.random.rand(3,1), lw = 2 );
pyplot.xlim( ( 0, w ) );
pyplot.ylim( ( h, 0 ) );

นี่เป็นวิธีที่น่าสนใจมาก ฉันสารภาพหัวข้อ "กราฟ" ถูกคลุมเครือกับฉันจนกระทั่งเมื่อเร็ว ๆ นี้เมื่อ (ในโครงการเดียวกันนี้) ฉันสามารถแก้ไขปัญหาอื่นได้โดยใช้กราฟ หลังจากที่ฉัน "เข้าใจ" ฉันรู้ว่าอัลกอริธึมเส้นทางลัดที่สั้นที่สุดเหล่านี้มีประสิทธิภาพแค่ไหน ความคิดของคุณน่าสนใจมากและเป็นไปไม่ได้ที่ฉันจะปรับใช้สำหรับสิ่งนี้หากฉันมีความต้องการ / โอกาส ขอบคุณมาก.
heltonbiker

สำหรับผลลัพธ์ปัจจุบันของคุณจากประสบการณ์ของฉันน่าจะดีกว่าที่จะปรับภาพให้เรียบก่อนด้วยตัวกรอง Gaussian และ / หรือค่ามัธยฐานก่อนสร้างกราฟ สิ่งนี้จะทำให้บรรทัด (และถูกต้องมากขึ้น) นุ่มนวลขึ้นมาก นอกจากนี้เคล็ดลับที่เป็นไปได้อย่างหนึ่งคือการขยายพื้นที่ใกล้เคียงเพื่ออนุญาตให้ "กระโดดโดยตรง" มากกว่าสองพิกเซลหรือมากกว่า แน่นอนควรเลือกฟังก์ชั่นค่าใช้จ่ายที่เหมาะสม แต่ฉันคิดว่ามันง่ายที่จะปรับ
heltonbiker

โอ้ใช่. ฉันเลือกบางอย่างที่อยู่ในมือคุณสามารถใช้ฟังก์ชันทอพอโลยีและพลังงานอื่น ๆ ได้ ที่จริงแล้วกรอบนี้ก็สามารถฝึกได้ โดยเฉพาะอย่างยิ่งคุณเริ่มต้นด้วยความเข้มแบบดิบถอดรหัสสำหรับเส้นทางที่ดีที่สุดรับเฉพาะโหนดที่ดีที่สุดที่มีความเชื่อมั่นสูงและด้วยวิธีนี้คุณจะได้รับ 'ข้อมูลที่มีป้ายกำกับ' ด้วยส่วนเล็ก ๆ ของข้อมูลที่มีป้ายกำกับโดยอัตโนมัตินี้คุณสามารถเรียนรู้สิ่งต่าง ๆ ที่มีประโยชน์มากมาย
หลุมพราง

3

คิดว่าฉันควรโพสต์คำตอบของฉันเพราะมันต่างจากวิธีอื่นเล็กน้อย ฉันลองสิ่งนี้ใน Matlab

  • รวมช่องสัญญาณทั้งหมดและสร้างภาพดังนั้นช่องทั้งหมดจึงมีน้ำหนักเท่ากัน
  • ทำการปิดทางสัณฐานวิทยาและการกรองแบบเกาส์บนภาพนี้
  • สำหรับแต่ละคอลัมน์ของอิมเมจผลลัพธ์ให้หา maxima โลคัลและสร้างอิมเมจ
  • ค้นหาส่วนประกอบที่เชื่อมต่อของภาพนี้

ข้อเสียอย่างหนึ่งที่ฉันเห็นที่นี่คือวิธีการนี้จะทำงานได้ไม่ดีนักสำหรับทิศทางของแถบ ในกรณีนั้นเราต้องแก้ไขการวางแนวและใช้ขั้นตอนนี้

นี่คือรหัส Matlab:

im = imread('m0sy7.png');
imsum = sum(im, 3); % sum all channels
h = fspecial('gaussian', 3);
im2 = imclose(imsum, ones(3)); % close
im2 = imfilter(im2, h); % smooth
% for each column, find regional max
mx = zeros(size(im2));
for c = 1:size(im2, 2)
    mx(:, c) = imregionalmax(im2(:, c));
end
% find connected components
ccomp = bwlabel(mx);

ตัวอย่างเช่นหากคุณใช้คอลัมน์กลางของภาพโปรไฟล์ควรมีลักษณะดังนี้: (สีน้ำเงินเป็นโปรไฟล์ส่วนสีเขียวคือค่าสูงสุดในท้องถิ่น) โปรไฟล์กลางและ maxima ท้องถิ่น

และภาพที่มี maxima ท้องถิ่นสำหรับคอลัมน์ทั้งหมดจะมีลักษณะดังนี้: ป้อนคำอธิบายรูปภาพที่นี่

นี่คือส่วนประกอบที่เชื่อมต่อ (แม้ว่าแถบบางเส้นจะหัก แต่ส่วนใหญ่จะเป็นพื้นที่ต่อเนื่อง):

ป้อนคำอธิบายรูปภาพที่นี่


นี่คือสิ่งที่เรากำลังทำอยู่ตอนนี้มีความแตกต่างเพียงวิธีการหาสูงสุดในท้องถิ่นสำหรับแต่ละคอลัมน์พิกเซล: เราใช้การแก้ไขพาราโบลาเพื่อหาจุดสุดยอดที่แท้จริงของพาราโบลาผ่านพิกเซลที่มีค่าสูงสุดและเพื่อนบ้านบนและล่าง . สิ่งนี้อนุญาตให้ s เป็นผลลัพธ์ที่ได้คือ "ระหว่าง" พิกเซลซึ่งจะแสดงถึงความเรียบเนียนของเส้นที่ละเอียดยิ่งขึ้น ขอบคุณสำหรับคำตอบ!
heltonbiker
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.