2016-04-04 3 views
6

मैं कुछ चीजें करके ओपनसीवी सीखने की कोशिश कर रहा हूं। इस विशेष मामले में, मैं एक ग्रेस्केल छवि के छोटे विमान लेना चाहता था। कोड काम करता प्रतीत होता है, लेकिन यह केवल 7 और 6 के लिए अच्छा काम करता है, शेष 6 के लिए इतना नहीं, क्योंकि यह केवल छवि के 1/3 के लिए एक अच्छा परिणाम दिखाता है। मुझे अभी तक यह नहीं मिला है कि इसके साथ क्या गलत है। मैं इस मामले पर कुछ मदद की सराहना करता हूं, क्योंकि मैं पुस्तकालयों के साथ अपना पहला कोड कर रहा हूं।ओपनसीवी में 1-प्लेन छवि के बिट विमान केवल छवि के 1/3 के लिए काम करते हैं

यहाँ मैं पहली बिट के लिए क्या मिलता है:

enter image description here

और यहाँ 7 बिट के लिए यह है:

enter image description here

और यहाँ मेरे कोड है:

#include <opencv2\opencv.hpp> 
#include <math.h> 

using namespace cv; 
using namespace std; 

int main(int argc, char** argv) { 
    Mat m1 = imread("grayscalerose.jpg"); 
    imshow("Original",m1); 
    int cols, rows, x, y; 
    cols = m1.cols; 
    rows = m1.rows; 
    printf("%d %d \n",m1.rows,m1.cols); 
    Mat out1(rows, cols, CV_8UC1, Scalar(0)); 
    out1 = (m1/128); //Here's where I divide by either 1,2,4,8,16,32,64, or 128 to get the corresponding bit planes 

    for (int y = 0; y < rows; y++){ 
     for (int x = 0; x < cols; x++){ 
      out1.at<uchar>(y,x) = (out1.at<uchar>(y,x) % 2); 
    } } 

    out1 = out1*255; 
    imshow("out1",out1); 
    waitKey(0); 
    destroyWindow("out1"); 

} 

अग्रिम धन्यवाद। मुझे उम्मीद है कि मेरी व्याख्या बहुत गन्दा नहीं थी।

उत्तर

3

जब आप विभाजित 15 (0x00001111) द्वारा 2 (0x00000010) आप 7 (0x00000111) मिलता है, जो नहीं है कि तुम क्या उम्मीद करते हैं। आप यह जांच सकते हैं कि थोड़ा सा सेट किया गया है: 15 & 2, जो 0 बिट बनाता है यदि दूसरा बिट सेट नहीं है, तो 0 से अधिक मान अधिक है। यह अन्य मानों के लिए भी लागू होता है।

निम्नलिखित कोड आज़माएं। ध्यान दें कि:

  • आप ग्रेस्केल के रूप में छवि को लोड करने की जरूरत है (का उपयोग कर imread में IMREAD_GRAYSCALE)
  • आप सीधे मूल्यों डाल सकते हैं या तो 0 या 255 जब आप बिट का चयन

कोड:

#include <opencv2/opencv.hpp> 
using namespace cv; 

int main() 
{ 
    Mat m1 = imread("path_to_image", IMREAD_GRAYSCALE); 
    imshow("Original", m1); 
    int cols, rows, x, y; 
    cols = m1.cols; 
    rows = m1.rows; 
    printf("%d %d \n", m1.rows, m1.cols); 
    Mat out1(rows, cols, CV_8UC1, Scalar(0)); 


    for (int y = 0; y < rows; y++){ 
     for (int x = 0; x < cols; x++){ 
      out1.at<uchar>(y, x) = (m1.at<uchar>(y, x) & uchar(64)) ? uchar(255) : uchar(0); //Here's where I AND by either 1,2,4,8,16,32,64, or 128 to get the corresponding bit planes 
     } 
    } 

    imshow("out1", out1); 
    waitKey(0); 
    destroyWindow("out1"); 

    return 0; 
} 
1

डिफ़ॉल्ट रूप से, cv::imread छवि को बीजीआर मैट्रिक्स के रूप में पढ़ता है, लेकिन आप मैट्रिक्स को इंडेक्स करते हैं जैसे कि यह एक-चैनल था।

बस पढ़ने की लाइन को Mat m1 = imread("grayscalerose.jpg", 0); पर बदलें और यह ठीक काम करेगा।

4

सबसे पहले छवि को केवल ग्रेस्केल के रूप में पढ़ें। (जैसा कि user3896254 द्वारा वर्णित है)।

फिर, के एक मुखौटा छवि, जहां केवल कम से कम महत्वपूर्ण बिट सेट किया गया है तैयार करते हैं - अर्थात सभी मूल्यों 1.

फिर एल्गोरिथ्म सरल है। आइए प्रति-पिक्सेल मैनिपुलेशन (लूप के लिए दो नेस्टेड) ​​से बचें, और ओपनसीवी द्वारा प्रदान किए गए अनुकूलित संचालन का लाभ उठाने का प्रयास करें।

प्रत्येक बिट (0..7) के लिए:

  • बाहर मास्क काम छवि में सबसे कम आदेश बिट।
  • इसे काले/सफेद बनाने के लिए 255 तक मुखौटा छवि स्केल करें।
  • आउटपुट स्टोर करें।
  • कार्य छवि में मूल्यों को विभाजित करें 2 - यानी सभी बिट्स को 1 स्थिति से दाएं स्थानांतरित करें।

कोड:

#include <opencv2\opencv.hpp> 
#include <cstdint> 

int main(int argc, char** argv) 
{ 
    cv::Mat input_img(cv::imread("peppers.png", 0)); 

    int32_t rows(input_img.rows), cols(input_img.cols); 

    cv::Mat bit_mask(cv::Mat::ones(rows, cols, CV_8UC1)); 

    cv::Mat work_img(input_img.clone()); 
    std::string file_name("peppers_bit0.png"); 
    for (uint32_t i(0); i < 8; ++i) { 
     cv::Mat out; 
     cv::bitwise_and(work_img, bit_mask, out); 

     out *= 255; 
     cv::imwrite(file_name, out); 

     work_img = work_img/2; 
     file_name[11] += 1; 
    } 
} 

हम भी कम (और शायद तेजी से) संस्करण एक भी matrix expression का उपयोग कर विकसित कर सकते हैं।

हम (1<<i) अभिव्यक्ति का उपयोग करके उचित विभाजक की गणना कर सकते हैं।

#include <opencv2\opencv.hpp> 
#include <cstdint> 

int main(int argc, char** argv) 
{ 
    cv::Mat input_img(cv::imread("peppers.png", 0)); 

    std::string file_name("peppers_bit0.png"); 
    for (uint32_t i(0); i < 8; ++i) { 
     cv::Mat out(((input_img/(1<<i)) & 1) * 255); 
     cv::imwrite(file_name, out); 

     file_name[11] += 1; 
    } 
} 

नमूना रन

इनपुट छवि:: हम, बिट्स बदलाव 1 के साथ यह Anding द्वारा प्रत्येक तत्व मुखौटा, और फिर 255 से सभी तत्वों पैमाने पर करने के लिए इस मान से हर तत्व को विभाजित

बिट 0:

बिट 1:

बिट 2:

बिट 3:

बिट 4:

बिट 5:

बिट 6:

बिट 7:

+0

मेरे साथ इस तरह के विस्तृत उत्तर साझा करने के लिए धन्यवाद। मुझे कबूल करना होगा, मैट्रिक्स अभिव्यक्ति के बारे में हिस्सा और uint32_t का उपयोग मेरे लिए बहुत स्पष्ट नहीं है। अगर मैं पूछूं, तो वे वास्तव में कैसे काम करते हैं? –

+1

@ डी। सैंज़ 'uint32_t' एक असाइन किए गए पूर्णांक 32 बिट चौड़े के लिए सिर्फ एक [मानक टाइपपीफ] (http://en.cppreference.com/w/cpp/header/cstdint) है। मैं स्पष्ट होना पसंद करता हूं, इसलिए यह स्पष्ट है कि मैं किस प्रकार का काम करता हूं इससे कोई फर्क नहीं पड़ता कि मैं किस मंच पर कोड संकलित करता हूं। –

+0

@ डी। सैंज मैट्रिक्स अभिव्यक्तियों के संबंध में: ओपनसीवी लिखा गया है, [अंकगणितीय परिचालन] (http://docs.opencv.org/2.4/modules/core/doc/operations_on_arrays.html) सरणी पर "मैट्रिक्स अभिव्यक्ति" (एक विशेष प्रकार)। एक ही सी ++ अभिव्यक्ति में उन परिचालनों की एक संयोजन को संकलक को अनुकूलित कोड उत्पन्न करने की अनुमति देता है। –

-1

Mat Out (In/(1<<i)), इसका विभाजन एक पूर्णांक मान उत्पन्न करेगा जो "राउंड ऑपरेशन" के बराबर होगा, मान लें कि अगर मैट आउट (6/5) 2 होगा। लेकिन, बिट-स्लाइसिंग में, यह फ़्लोर ऑपरेशन का उपयोग करता है गोल। इस प्रकार, मैट आउट (6/5) के लिए यह 2 के बजाय 1 होना चाहिए। कुछ मामलों के लिए, परिणाम काफी समान होगा। लेकिन, अन्य मामलों में, यह वास्तव में अलग हो सकता है, खासकर एमएसबी (सबसे महत्वपूर्ण बिट्स) के पास बिट-प्लेन के लिए। CMIIW।

+0

मेरी टिप्पणी केवल शुरुआत में केवल थोड़ी सी क्यों दिखाई देती है? पूर्ण टिप्पणी: @ डैन मासेक: लेकिन, मैट आउट (इन/(1 << i)), इसका विभाजन एक पूर्णांक मान उत्पन्न करेगा जो "राउंड ऑपरेशन" के बराबर होगा, मान लें कि अगर मैट आउट (6/5) 2 होगा। लेकिन, थोड़ा-टुकड़ा करने में, यह गोल के बजाय फर्श ऑपरेशन का उपयोग करता है। इस प्रकार, मैट आउट (6/5) के लिए यह 2 के बजाय 1 होना चाहिए। इसी मामले में, वह परिणाम काफी समान होगा। लेकिन, अन्य मामलों में, यह वास्तव में अलग हो सकता है, खासकर एमएसबी (सबसे महत्वपूर्ण बिट्स) के पास बिट-प्लेन के लिए। CMIIW। – Ardian

संबंधित मुद्दे