이미지에서 지브라와 같은 패턴 찾기 (사진에서 구조 광 프린지 중심선 감지)


12

프린지가 피사체에 투사되고 사진이 찍히는 프로젝트에서 일하고 있습니다. 과제는 프린지 평면과 대상 표면 사이의 3D 교차 곡선을 수학적으로 나타내는 프린지의 중심선을 찾는 것입니다.

사진은 PNG (RGB)이며 이전의 시도에서는 그레이 스케일링과 차이 임계 값을 사용하여 흑백 "얼룩말 같은"사진을 찍었습니다.이 사진에서 각 프린지의 각 픽셀 열의 중간 점을 쉽게 찾을 수있었습니다. 문제는 임계 값을 설정하고 이산 픽셀 열의 평균 높이를 취함으로써 약간의 정밀 손실과 양자화가 발생한다는 것입니다.

이미지를 살펴본 결과, 임계 값이없는 이미지 (RGB 또는 그레이 스케일)에서 통계 스위핑 방법으로 직접 감지 된 경우 중심선이 더 연속적이며 (더 많은 포인트) 매끄럽게 (양자화되지 않음) 수 있습니다. (일부 범람 / 반복 컨볼 루션 등).

아래는 실제 샘플 이미지입니다.

여기에 이미지 설명을 입력하십시오

어떤 제안이라도 대단히 감사하겠습니다!


매우 흥미 롭습니다. 그러나 그건 그렇고, 컬러 스트라이프를 사용하여 3D 물체를 감지하는 연구를하고 있습니다. 컬러 스트라이프를 사용하기 때문에 프로젝터에서 각 스트라이프의 대응 관계를 쉽게 찾을 수 있으므로 삼각법을 사용하여 3D 정보를 계산할 수 있습니다. 색상이 같은 경우 어떻게 대응 관계를 찾습니까? 프로젝트가 3D 재구성에 관한 것 같아요?

@ johnyoung : 답변으로 의견을 추가하지 마십시오. 의견을 제시하기 전에 평판이 필요하다는 것을 알고 있지만 현재 행동을 삼가십시오. 귀하의 담당자를 늘리기 위해 자신의 (관련된) 질문을하거나 다른 사람의 질문에 대답하는 것이 좋습니다.
Peter K.

대답 대신에 하나의 질문에 대해 죄송합니다. 위상 이동 방법에서는 투영 된 이미지의 각 픽셀에서 위상을 계산하지만 프린지의 중심선을 찾아야하는 이유는 무엇입니까? 내 질문은 어리석은 일이지만 아니, 그러니 정확한 이유를 알려줘 U는 답변을주고 나서 내 질문을 삭제할 수 있습니다

이들은 다른 방법입니다. 일련의 흰색 줄무늬 (각각 3D 공간에서 "평면"을 형성하는)를 투영하여 일련의 기하학적 평면을 모델링하고 있습니다. 따라서 평면에는 두께가 없으므로 프린지 중심선을 찾아야합니다. 물론 위상 편이 분석을 수행 할 수는 있지만 한 가지 문제가 있습니다. 프로젝션이 이진 (흑백 줄무늬가 번갈아 가며), 강도가 사인 곡선으로 변하지 않기 때문에 위상 변이를 수행 할 수 없습니다 (현재 필요하지 않음). ).
heltonbiker

답변:


13

다음 단계를 제안합니다.

  1. 전경과 배경을 구분하기위한 임계 값을 찾으십시오.
  2. 이진 이미지의 각 얼룩 (하나의 얼룩말 줄무늬)에 대해 방향별로 x가중치 중심 (픽셀 강도 기준)을 찾습니다 y.
  3. y노이즈를 제거하기 위해 값을 부드럽게 할 수 있습니다.
  4. (x,y)어떤 종류의 곡선을 피팅 하여 점을 연결하십시오 . 이 기사 가 도움 될 수 있습니다. 내 의견으로는 더 나쁘지만 높은 수준의 다항식에 적합 할 수도 있습니다.

1, 2, 4 단계를 보여주는 Matlab 코드는 다음과 같습니다. 자동 임계 값 선택을 건너 뛰었습니다. 대신 수동을 선택했습니다 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

나는 이것이 매우 흥미로운 것을 알았다. 나는 파이썬을 사용하지만 어쨌든 나는이 모든 것의 근거를 연구해야 할 것이다. 독립적 인 의견으로, 나는 고전적인 이미지 처리를 수행하지 않는 경향이 있지만 (uint8 배열과 같은 양자화 된 이미지 컨테이너에서 직접) 대신 작업을 적용하기 전에 모든 것을 부동 배열로 메모리에로드합니다. 또한 이미지 하단부의 결과에 놀랐습니다. 파란색 선이 예상 프린지 중간 선을 따라 실행되지 않습니다 ... (?). 감사합니다. 결과를 얻 자마자 의견을 보내겠습니다.
heltonbiker

@heltonbiker, 업데이트 된 답변을 확인하십시오. 부동 소수점에 대해 맞습니다 double. 로 변환 할 때 사용했습니다 . 하단의 결과에 대해, 내가 확인해야합니다, 그것은 소프트웨어 버그 수 있습니다
안드레이 Rubshtein

1
@heltonbiker, 완료. 실제로 1 기반 인덱싱과 관련된 버그였습니다.
Andrey Rubshtein

엑설런트! 정말 놀랍습니다. 이 기술을 사용하면 저의 목적으로 스무딩이 필요할뿐만 아니라 해로울 수 있습니다. 관심을 가져 주셔서 감사합니다!
heltonbiker

3

RGB 이미지를 사용하지 않습니다. 컬러 이미지는 일반적으로 카메라 센서에 "바이어 필터" 를 장착하여 만들어 지므로 일반적으로 얻을 수있는 해상도가 줄어 듭니다.

회색조 이미지를 사용하는 경우 설명한 단계 ( "얼룩말 이미지를 이진화, 중간 선 찾기")가 좋은 시작이라고 생각합니다. 마지막 단계로

  • 찾은 중간 선에서 각 지점을 가져 가십시오.
  • 위와 아래의 "얼룩말"선에있는 픽셀의 회색 값을 가져옵니다
  • 최소 평균 제곱을 사용하여 포물선을이 회색 값에 맞추십시오
  • 이 포물선의 정점은 개선 된 미드 라인 위치입니다

좋은 생각. 각 픽셀 열의 피크 값을 따라 일종의 포물선 또는 스플라인을 사용할 계획이지만 여전히 라인을 따라 픽셀 열 또는 픽셀 "영역"을 검사해야하는지 궁금합니다. 더 많은 답변. 고마워요!
heltonbiker

@heltonbiker-빠른 테스트로 녹색 채널 만 사용하십시오. 이 일반적이다 컬러 센서에 많은 녹색 픽셀로 2 배 그것은 덜 빨간색과 파란색보다 interpoalted한다
마틴 베켓

@MartinBeckett 관심을 가져 주셔서 감사합니다. 이미 각 채널을 분석했으며 실제로 녹색 채널은 빨간색 채널보다 훨씬 더 해결 된 것으로 보입니다. 그러나 각 채널에 대한 수직 단면의 강도 값을 플로팅하면 "스트라이프 패턴"이 채널간에 크게 변경되지 않는 것으로 보이며 현재 그레이 스케일로 변환 할 때 균등하게 혼합하고 있습니다. 그럼에도 불구하고 여전히 최고의 대비 결과를 얻거나 이미 회색조로 이미지를 획득하기 위해 채널 간의 최상의 선형 조합을 연구 할 계획입니다. 다시 감사합니다!
heltonbiker

3

다음은 질문을 '경로 최적화 문제'로 모델링하여 문제에 대한 대안 솔루션입니다. 단순한 이진화 및 곡선 화 솔루션보다 더 복잡하지만 실제로는 더욱 강력합니다.

매우 높은 수준에서이 이미지를 그래프로 고려해야합니다. 여기서

  1. 각 이미지 픽셀은이 그래프의 노드입니다

  2. 각 노드는 이웃이라고 알려진 다른 노드에 연결되며이 연결 정의를 종종이 그래프의 토폴로지라고합니다.

  3. 각 노드에는 가중치 (기능, 비용, 에너지 또는 호출하려는 대상)가 있으며이 노드가 원하는 최적의 중심선에있을 가능성을 반영합니다.

이러한 가능성을 모형화 할 수있는 한, '프린지의 중심선'을 찾는 문제 는 그래프 에서 로컬 최적 경로찾는 문제가되며 Viterbi 알고리즘과 같은 동적 프로그래밍으로 효과적으로 해결할 수 있습니다.

이 접근법을 채택하는 몇 가지 장점은 다음과 같습니다.

  1. 하나의 중심선을 여러 조각으로 나눌 수있는 임계 값 방법과 달리 모든 결과는 연속적입니다.

  2. 이러한 그래프를 구성 할 수있는 자유가 많으면 다른 기능과 그래프 토폴로지를 선택할 수 있습니다.

  3. 경로 최적화의 관점에서 결과가 최적입니다

  4. 노이즈가 모든 픽셀에 균등하게 분산되어 있으면 최적의 경로가 안정적으로 유지되므로 솔루션이 노이즈에 대해 더욱 강력 해집니다.

위의 아이디어에 대한 간단한 데모가 있습니다. 가능한 시작 및 종료 노드를 지정하기 위해 사전 지식을 사용하지 않기 때문에 가능한 모든 시작 노드에서 wrt를 단순히 디코딩합니다. 해독 된 비터 비 경로

퍼지 엔딩의 경우 가능한 모든 엔딩 노드에 대한 최적의 경로를 찾고 있기 때문입니다. 결과적으로 어두운 영역에 위치한 일부 노드의 경우 강조 표시된 경로는 여전히 로컬 최적 경로입니다.

퍼지 경로의 경우 찾은 후 매끄럽게하거나 원시 강도 대신 매끄럽게 한 일부 기능을 사용할 수 있습니다.

시작 및 종료 노드를 변경하여 부분 경로를 복원 할 수 있습니다.

이 바람직하지 않은 지역 최적 경로를 정리하는 것은 어렵지 않습니다. 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

현재의 결과와 관련하여 내 경험상 그래프를 작성하기 전에 가우시안 및 / 또는 중간 필터로 이미지를 부드럽게하는 것이 좋습니다. 이것은 훨씬 더 부드럽고 정확한 선을 줄 것입니다. 또한, 하나의 가능한 트릭은 이웃을 확장하여 2 개 이상의 픽셀 (최대 8, 10 픽셀)까지 "직접 점프"할 수 있도록하는 것입니다. 물론 적절한 비용 함수를 선택해야하지만 조정하기 쉽다고 생각합니다.
heltonbiker

바로 이거 야. 나는 단순히 손에 든 것을 골랐다. 다른 토폴로지와 에너지 기능을 확실히 사용할 수있다. 실제로이 프레임 워크도 훈련 가능합니다. 특히, 원시 강도부터 시작하여 최적의 경로를 디코딩하고 높은 신뢰도로 최적의 노드 만 선택하면 이러한 방식으로 '라벨 된 데이터'를 얻을 수 있습니다. 자동으로 레이블이 지정된 데이터의이 작은 부분을 통해 많은 종류의 유용한 것을 배울 수 있습니다.
함정

3

다른 접근 방식과 약간 다르므로 답변을 게시해야한다고 생각했습니다. 나는 이것을 Matlab에서 시도했다.

  • 모든 채널을 합산하고 이미지를 생성하므로 모든 채널의 가중치가 동일
  • 이 이미지에서 형태 학적 클로징 및 가우시안 필터링 수행
  • 결과 이미지의 각 열에 대해 로컬 최대 값을 찾아 이미지를 구성하십시오.
  • 이 이미지의 연결된 구성 요소를 찾습니다

여기서 볼 수있는 한 가지 단점은이 방법이 줄무늬의 일부 방향에서는 제대로 수행되지 않는다는 것입니다. 이 경우 방향을 수정하고이 절차를 적용해야합니다.

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);

예를 들어 이미지의 중간 열을 가져 오면 해당 프로필은 다음과 같아야합니다 (파란색은 프로필입니다. 초록색은 로컬 최대 값입니다) 중간 프로파일 및 로컬 최대 값

모든 열에 대한 로컬 최대 값을 포함하는 이미지는 다음과 같습니다. 여기에 이미지 설명을 입력하십시오

연결된 구성 요소는 다음과 같습니다 (일부 줄무늬는 끊어졌지만 대부분 연속 영역이 나타남).

여기에 이미지 설명을 입력하십시오


이것은 실제로 우리가 지금하고있는 일입니다. 각 픽셀 열에 대해 로컬 최대 값을 찾는 방법은 유일한 차이입니다. 포물선 보간법을 사용하여 최대 값과 상위 및 하위 이웃이있는 픽셀을 통과하는 포물선의 정확한 정점을 찾습니다. . 이것은 결과가 "사이에"픽셀이되도록하여 선의 미묘한 매끄러움을 더 잘 나타낸다. 답변 주셔서 감사합니다!
heltonbiker '11
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.