2012-03-23 24 views
7

私はOpenCV-2.3 APIを使ってC++で小さなプログラムを書いています。 私は、非長方形マスクを使用して適応しきい値を処理する問題があります。適応型しきい値を持つマスクを使用していますか?

これまでのところ、全体の画像に対して適応的なしきい値を実行し、後でマスクしていました。私は、私の場合、マスクされたピクセルが関心のあるピクセルの閾値を計算するために使用されるので、これは間違いであることを認識しています(私は単純に解析から除外したい)... しかし、 cv :: normとして、cv :: adaptiveThresholdは明示的にマスクをサポートしていないようです。

明らかな解決策または回避策をご存知ですか? あなたの提案を非常にうかがっていただき、ありがとうございます。 Quentin

答えて

3

私は、マスクされた適応型閾値処理を可能にするPythonコードを書いています。それほど高速ではありませんが、あなたが望むことを実行し、C++コードの基礎として使用することができます。

  1. イメージのマスクされたピクセルをゼロに設定します。
  2. 各ピクセルのコンボリューションブロック内のマスクされていないネイバーの数を決定します。
  3. 畳み込みを実行し、ブロック内のマスクされていないネイバーの数で平均します。これにより、ピクセル近傍ブロック内の平均値が得られます。
  4. しきい値と画像を平均近傍値と比較して、mean_conv
  5. 画像のマスクされていない(閾値なしの)部分を戻します。

enter image description here

画像は、初期画像、マスク、最終処理画像を示します。

は、ここでは、コードです:

import cv 
import numpy 
from scipy import signal 

def thresh(a, b, max_value, C): 
    return max_value if a > b - C else 0 

def mask(a,b): 
    return a if b > 100 else 0 

def unmask(a,b,c): 
    return b if c > 100 else a 

v_unmask = numpy.vectorize(unmask) 
v_mask = numpy.vectorize(mask) 
v_thresh = numpy.vectorize(thresh) 

def block_size(size): 
    block = numpy.ones((size, size), dtype='d') 
    block[(size - 1)/2, (size - 1)/2] = 0 
    return block 

def get_number_neighbours(mask,block): 
    '''returns number of unmasked neighbours of every element within block''' 
    mask = mask/255.0 
    return signal.convolve2d(mask, block, mode='same', boundary='symm') 

def masked_adaptive_threshold(image,mask,max_value,size,C): 
    '''thresholds only using the unmasked elements''' 
    block = block_size(size) 
    conv = signal.convolve2d(image, block, mode='same', boundary='symm') 
    mean_conv = conv/get_number_neighbours(mask,block) 
    return v_thresh(image, mean_conv, max_value,C) 

image = cv.LoadImageM("image.png", cv.CV_LOAD_IMAGE_GRAYSCALE) 
mask = cv.LoadImageM("mask.png", cv.CV_LOAD_IMAGE_GRAYSCALE) 

#change the images to numpy arrays 
original_image = numpy.asarray(image) 
mask = numpy.asarray(mask) 
# Masks the image, by removing all masked pixels. 
# Elements for mask > 100, will be processed 
image = v_mask(original_image, mask) 
# convolution parameters, size and C are crucial. See discussion in link below. 
image = masked_adaptive_threshold(image,mask,max_value=255,size=7,C=5) 
# puts the original masked off region of the image back 
image = v_unmask(original_image, image, mask) 
#change to suitable type for opencv 
image = image.astype(numpy.uint8) 
#convert back to cvmat 
image = cv.fromarray(image) 

cv.ShowImage('image', image) 
#cv.SaveImage('final.png',image) 
cv.WaitKey(0) 

私は画像の例をたっぷり使って良い説明がありthis great linkを発見し、これを書き込んだ後、私は上記の例のために彼らのテキスト画像を使用していました。

注。ナンシーなマスクはscipy signal.convolve2d()によって尊重されていないようですので、上記の回避策が必要でした。

+0

ありがとうございましたあなたの答えをありがとうございました。 私はあなたの提案を調査しています。 Quentin –

+0

@Quentin Geissmann - あなたのC++コードでうまく動作しましたか? – fraxel

+0

私はそれを非常に遅くすることなく実装する方法を理解していると思います... しかし、まだ実装されていません。 :) ありがとう –

3

あなたのアドバイスにしたがって、あなたのリンクを読んだ後、私はこの小さなC++関数を書きました: これは適応閾値よりわずか1.5ですが、おそらくそれを改善することができます。

void adaptiveThresholdMask(const cv::Mat src,cv::Mat &dst, double maxValue,  cv::Mat mask, int thresholdType, int blockSize, double C){ 
cv::Mat img, invertMask, noN, conv,kernel(cv::Size(blockSize,blockSize),CV_32F); 

/* Makes a image copy of the source image*/ 
src.copyTo(img); 

/* Negates the mask*/ 
cv::bitwise_not(mask,invertMask); 

/* Sets to 0 all pixels out of the mask*/ 
img = img-invertMask; 
/* The two following tasks are both intensive and 
* can be done in parallel (here with OpenMP)*/ 
#pragma omp parallel sections 
{ 
    { 
     /* Convolves "img" each pixels takes the average value of all the pixels in blocksize*/ 
     cv::blur(img,conv,cv::Size(blockSize,blockSize)); 
    } 
    #pragma omp section 
    { 
     /* The result of bluring "mask" is proportional to the number of neighbours */ 
     cv::blur(mask,noN,cv::Size(blockSize,blockSize)); 
    } 
} 

/* Makes a ratio between the convolved image and the number of 
* neighbours and subtracts from the original image*/ 
if(thresholdType==cv::THRESH_BINARY_INV){ 
    img=255*(conv/noN)-img; 
    } 
else{ 
    img=img-255*(conv/noN); 
    } 

/* Thresholds by the user defined C*/ 
cv::threshold(img,dst,C,maxValue,cv::THRESH_BINARY); 

/* We do not want to keep pixels outside of the mask*/ 
cv::bitwise_and(mask,dst,dst); 

} 

+0

nice one :)私は私のPythonコードを大幅に高速化できると思っています。私はいくつかの時点でそれを試してみます。 – fraxel

+0

私はこの解決策を理解していません。このスピードアップバージョンの仕組みを詳しく説明できますか?私はopencv-pythonに移植しようとしましたが、成功しませんでした。 – pzo

+0

非常に素晴らしいソリューションで、(Pythonでテストされた)超高速ですが、画像が暗すぎると少し不正確になります。ぼかし操作。 – letmaik

関連する問題