2012-03-05 14 views
17

पोस्टरइज़ करने के लिए के-साधन का उपयोग करके ओपनसीवी सी ++ इंटरफ़ेस (सीवी नेमस्पेस) में के-साधन और ओपनसीवी के साथ एक छवि पोस्टरइज़ करना चाहता हूं और मुझे अजीब परिणाम मिलते हैं। मुझे कुछ शोर को कम करने के लिए इसकी ज़रूरत है। यह मेरा कोड है:ओपनसीवी एक छवि

#include "cv.h" 
#include "highgui.h" 

using namespace cv; 

int main() { 
    Mat imageBGR, imageHSV, planeH, planeS, planeV; 

    imageBGR = imread("fruits.jpg"); 
    imshow("original", imageBGR); 

    cv::Mat labels, data; 
    cv::Mat centers(8, 1, CV_32FC1); 
    imageBGR.convertTo(data, CV_32F); 

    cv::kmeans(data, 8, labels, 
      cv::TermCriteria(CV_TERMCRIT_ITER, 10, 1.0), 
      3, cv::KMEANS_PP_CENTERS, &centers); 
    imshow("posterized hue", data); 
    data.convertTo(data, CV_32FC3); 

    waitKey(); 
    return 0; 
} 

लेकिन मैं एक अजीब परिणाम प्राप्त

Fruit

पहले छवि: मूल

दूसरा छवि: k-साधन के बाद।

कोई सलाह?


अद्यतन: सही समाधान। शायद कोई कोड को अनुकूलित करने में मेरी मदद कर सकता है?

#include "cv.h" 
#include "highgui.h" 

#include <iostream> 

using namespace cv; 
using namespace std; 

int main() { 
    Mat src; 

    src = imread("fruits.jpg"); 
    imshow("original", src); 

    blur(src, src, Size(15,15)); 
    imshow("blurred", src); 

    Mat p = Mat::zeros(src.cols*src.rows, 5, CV_32F); 
    Mat bestLabels, centers, clustered; 
    vector<Mat> bgr; 
    cv::split(src, bgr); 
    // i think there is a better way to split pixel bgr color 
    for(int i=0; i<src.cols*src.rows; i++) { 
     p.at<float>(i,0) = (i/src.cols)/src.rows; 
     p.at<float>(i,1) = (i%src.cols)/src.cols; 
     p.at<float>(i,2) = bgr[0].data[i]/255.0; 
     p.at<float>(i,3) = bgr[1].data[i]/255.0; 
     p.at<float>(i,4) = bgr[2].data[i]/255.0; 
    } 

    int K = 8; 
    cv::kmeans(p, K, bestLabels, 
      TermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 10, 1.0), 
      3, KMEANS_PP_CENTERS, centers); 

    int colors[K]; 
    for(int i=0; i<K; i++) { 
     colors[i] = 255/(i+1); 
    } 
    // i think there is a better way to do this mayebe some Mat::reshape? 
    clustered = Mat(src.rows, src.cols, CV_32F); 
    for(int i=0; i<src.cols*src.rows; i++) { 
     clustered.at<float>(i/src.cols, i%src.cols) = (float)(colors[bestLabels.at<int>(0,i)]); 
//  cout << bestLabels.at<int>(0,i) << " " << 
//    colors[bestLabels.at<int>(0,i)] << " " << 
//    clustered.at<float>(i/src.cols, i%src.cols) << " " << 
//    endl; 
    } 

    clustered.convertTo(clustered, CV_8U); 
    imshow("clustered", clustered); 

    waitKey(); 
    return 0; 
} 

परिणाम:

Posterized Fruit

+0

यह सिर्फ हो सकता है कि आप और अधिक पुनरावृत्तियों की जरूरत है और/या एक छोटा ईपीएसलॉन। मेरा सुझाव है कि आप अभी के लिए "CV_TERMCRIT_EPS" को हटाने का प्रयास करें, और अपने टर्मक्रिटिया में पुनरावृत्तियों की संख्या के साथ खेलो। देखें कि क्या मदद करता है। –

+0

मैं सिर्फ कंप्यूटर दृष्टि, छवि प्रसंस्करण और मशीन सीखने के करीब आ रहा हूं लेकिन मेरे लिए एक और गलती है जो मैं कर रहा हूं और न केवल पैरामीटर ठीक ट्यूनिंग .. – nkint

+0

मैं आपको पैरामीटर ट्यूनिंग शुरू करने का सुझाव नहीं दे रहा हूं, मैं हूं यह सुझाव देने के लिए कि आप जो कोशिश कर रहे हैं उसका सबसे बुनियादी रूप में काम करने के लिए आप अपने कोड को सरल बनाते हैं। ईपीएसलॉन को हटाने और पुनरावृत्तियों की संख्या में वृद्धि अनियंत्रित चालबाजी को हटा देती है। –

उत्तर

8

मैं OpenCV में कोई विशेषज्ञ हूँ तो मैं एक सामान्य सलाह है कि आपके सवाल का कश्मीर साधन से संबंधित है जो अनिवार्य रूप से एक मैट्रिक्स है वैक्टर की सूची लेता है दे देंगे:

[x0, y0, r0, g0, b0] 
[x1, y1, r1, g1, b1] 
[x2, y2, r2, g2, b2] 
. 
. 
. 

आप इसे एक छवि दे रहे हैं जो काम नहीं करेगा। आपको सबसे पहले छवि को इस के-साधन मैट्रिक्स प्रारूप में कनवर्ट करना होगा। स्रोत छवि के प्रत्येक पिक्सेल के लिए आपके परिणामस्वरूप मैट्रिक्स में एक पंक्ति है। यह भी ध्यान रखें कि आपको मूल्यों को स्केल करना चाहिए ताकि उनके सभी समान मूल्य हों। यदि आप ऐसा नहीं करते हैं, तो एक्स और वाई निर्देशांक आमतौर पर रंग की तुलना में अधिक "गुरुत्वाकर्षण" होते हैं जो असंतोषजनक परिणामों की ओर जाता है। सी ++ स्यूडोकोड:

int pixel_index = 0; 
for (int y = 0; y < image height; y++) { 
    for (int x = 0; x < image width; x++) { 
    matrix[pixel_index][0] = (float)x/image width; 
    matrix[pixel_index][1] = (float)y/image height; 
    matrix[pixel_index][2] = (float)pixel(x, y).r/255.0f; 
    matrix[pixel_index][3] = (float)pixel(x, y).g/255.0f; 
    matrix[pixel_index][4] = (float)pixel(x, y).b/255.0f; 
    } 
} 
// Pass the matrix to kmeans... 

नतीजतन, आप प्रत्येक व्यक्ति पिक्सेल जो क्लस्टर इसे करने के लिए सौंपा गया है से मेल खाती है के लेबल मिलता है। फिर आपको क्लस्टर के रंग को निर्धारित करने की आवश्यकता होती है - यह क्लस्टर के औसत/औसत रंग की गणना करने के लिए केंद्र पिक्सेल रंग मान लेने से भिन्न हो सकती है। के बाद आप रंग निर्धारित, बस छवि चलना और उनके क्लस्टर रंग के पिक्सल सेट:

for (int y = 0; y < image height; y++) { 
    for (int x = 0; x < image width; x++) { 
    int index = y * image width + x; // This corresponds to pixel_index above 
    int cluster_index = labels[index]; // 0 to 7 in your case 
    Color color = colors[cluster_index]; // Colors is an array of 8 colors of the clusters 
    image.setpixel(x, y, color) 
    } 
} 

आप आरजीबी के बजाय एचएसवी उपयोग करने के लिए पसंद करते हैं, बस आरजीबी लोगों के बजाय एचएसवी मूल्यों का उपयोग करें।

यह संभव है कि ओपनसीवी में ऐसे कार्य हैं जो ऊपर वर्णित रूपांतरण को निष्पादित करते हैं लेकिन मैं उन्हें Google का उपयोग करके तुरंत ढूंढने में असमर्थ था।

+0

क्षमा करें, लेकिन मुझे इस केमैन विशिष्ट इनपुट प्रारूप के बारे में जानकारी कहां मिल सकती है? – nkint

+0

ओपनसीवी दस्तावेज में (http: // opencv। willowgarage.com/documentation/cpp/clustering_and_search_in_multi-dimensional_spaces.html): 'नमूने - इनपुट नमूने के फ़्लोटिंग-पॉइंट मैट्रिक्स, एक नमूना प्रति पंक्ति' जहां नमूना का मतलब बहु आयामी बिंदु है। रंग छवि के मामले में, बिंदु है 5 आयाम (एक्स, वाई, आर, जी, बी)। यह केमैन करने का मानक तरीका है, ओपनसीवी सिर्फ अपने डेटा संरचनाओं का उपयोग करके इसे व्यक्त करता है। सामान्य केमन्स परिचय के लिए मैं मशीन पर सीखने वाले वीडियो के बारे में मशीन सीखने की सलाह देता हूं : //www.ml-class.org। –

+0

मैं पहले से ही सब्सक्राइब कर चुका हूं अगला कोर्स अभी शुरू होना है! :) – nkint

8

आप एक्स की जरूरत नहीं है, तो y अपने k-साधन में निर्देशांक, आप के रूप में आकृति बदलें आदेश का उपयोग इस प्रकार डेटा बहुत जल्दी व्यवस्था कर सकते हैं:

int origRows = img.rows; 
    notes << "original image is: " << img.rows << "x" << img.cols << endl; 
    Mat colVec = img.reshape(1, img.rows*img.cols); // change to a Nx3 column vector 
    cout << "colVec is of size: " << colVec.rows << "x" << colVec.cols << endl; 
    Mat colVecD, bestLabels, centers, clustered; 
    int attempts = 5; 
    int clusts = 8; 
    double eps = 0.001; 
    colVec.convertTo(colVecD, CV_32FC3, 1.0/255.0); // convert to floating point 
    double compactness = kmeans(colVecD, clusts, bestLabels, 
     TermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, attempts, eps), 
     attempts, KMEANS_PP_CENTERS, centers); 
    Mat labelsImg = bestLabels.reshape(1, origRows); // single channel image of labels 
    cout << "Compactness = " << compactness << endl; 
+0

अच्छा! अच्छा तरीका, मैं इसे करने का एक आसान तरीका ढूंढ रहा था! धन्यवाद! – nkint

+0

@zzzz फीचर वैक्टर में निर्देशांक को "स्थानिक समन्वय" के साथ मदद करनी चाहिए, है ना? यही है, यह समानांतर रंग वाले पिक्सल को समूहित करना पसंद करेगा और एक दूसरे के पास हैं। –

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