2012-03-23 66 views
7

Tôi đang viết một chương trình nhỏ trong C++ sử dụng API OpenCV-2.3. Tôi gặp sự cố khi xử lý ngưỡng thích ứng bằng mặt nạ không phải hình chữ nhật.Sử dụng mặt nạ có ngưỡng thích ứng?

Cho đến nay, tôi đã thực hiện ngưỡng thích ứng trên toàn bộ hình ảnh và mặt nạ sau đó. Tôi nhận ra rằng, trong trường hợp của tôi, đây là một sai lầm vì các pixel bị che khuất sẽ được sử dụng để tính toán ngưỡng pixel của tôi (trong khi tôi chỉ muốn loại trừ điểm ảnh cũ khỏi phân tích) ... Tuy nhiên, không giống như các chức năng như vậy như cv :: norm, cv :: adaptiveThreshold dường như không hỗ trợ rõ ràng một mặt nạ.

Bạn có biết giải pháp hoặc giải pháp rõ ràng nào không? Cảm ơn bạn rất muck cho các đề xuất của bạn, Quentin

Trả lời

3

Tôi đã viết một số mã Python (xin lỗi không phải C++) sẽ cho phép làm nổi bật mặt nạ thích ứng mặt nạ. Nó không phải là rất nhanh, nhưng nó làm những gì bạn muốn, và bạn có thể sử dụng nó làm cơ sở cho mã C++. Nó hoạt động như sau:

  1. Đặt pixel bị che khuất trong hình ảnh về 0.
  2. Xác định số lượng hàng xóm được che giấu trong khối chập đối với mỗi pixel.
  3. Thực hiện chuyển đổi và tính trung bình theo số lượng hàng xóm không được che giấu trong khối. Điều này mang lại giá trị trung bình trong khối vùng lân cận pixel.
  4. Ngưỡng, bằng cách so sánh hình ảnh với các giá trị khu vực trung bình, mean_conv
  5. Thêm phần mặt nạ (không được ngưỡng) của hình ảnh trở lại.

enter image description here

Những hình ảnh hiển thị, hình ảnh ban đầu, mặt nạ, hình ảnh chế biến thức.

Dưới đây là các mã:

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) 

Sau khi viết những dòng này tôi thấy this great link rằng có một lời giải thích tốt với nhiều mẫu hình ảnh, tôi đã sử dụng hình ảnh văn bản của họ đối với ví dụ trên.

Lưu ý. Mặt nạ gắt gỏng dường như không được tôn trọng bởi scipy signal.convolve2d(), vì vậy các cách giải quyết ở trên là cần thiết.

+0

Cảm ơn bạn rất nhiều vì câu trả lời của bạn. Tôi đang điều tra đề xuất của bạn. Quentin –

+0

@Quentin Geissmann - Bạn đã làm cho nó hoạt động trong mã C++ của bạn? – fraxel

+0

Tôi nghĩ rằng tôi hiểu cách thực hiện mà không làm cho nó rất chậm ... Nhưng chưa được triển khai. :) cảm ơn bạn –

3

Theo lời khuyên của bạn, và sau khi đọc liên kết của bạn, tôi đã viết hàm C++ nhỏ này: Chỉ chậm hơn 1.5 so với ngưỡng thích ứng, nhưng tôi có thể cải thiện nó.

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

} 

Cảm ơn bạn một lần nữa

+0

nice one :) Tôi nghĩ rằng tôi có thể tăng tốc mã python của tôi rất nhiều, tôi sẽ cố gắng và tìm hiểu nó ở một số điểm. – fraxel

+0

Tôi không hiểu giải pháp này. Bạn có thể giải thích cách phiên bản tăng tốc này hoạt động không? Tôi đã cố gắng chuyển nó sang opencv-python nhưng không thành công – pzo

+0

Đó là một giải pháp rất hay và siêu nhanh (được thử bằng Python), mặc dù nó trở nên không chính xác khi ảnh của bạn rất tối, vì sau đó bạn làm xước độ phân giải số nguyên do các hoạt động mờ. – letmaik

Các vấn đề liên quan