2013-09-28 5 views
22

के साथ शिफ्ट छवि सामग्री, छवि से शुरू होने पर, मैं आकार को बदलने के बिना और उप छवि width x 10 को काले रंग के नीचे भरने के बिना अपनी सामग्री को 10 पिक्सेल के शीर्ष पर स्थानांतरित करना चाहता हूं।ओपनसीवी

उदाहरण के लिए

, मूल:

Original

और स्थानांतरित कर दिया:

Shifted

वहाँ OpenCV के साथ सीधे यह कार्रवाई करने के लिए एक समारोह है?

the OpenCV documentation से सीधे लिया गया:

उत्तर

25

क्या ओपनसीवी के साथ इस ऑपरेशन को सीधे करने के लिए कोई फ़ंक्शन है?

http://code.opencv.org/issues/2299

या आप इस

cv::Mat out = cv::Mat::zeros(frame.size(), frame.type()); 
    frame(cv::Rect(0,10, frame.cols,frame.rows-10)).copyTo(out(cv::Rect(0,0,frame.cols,frame.rows-10))); 
+0

यह थोड़ा सा बुरा चाल है। यह काम करता है, लेकिन "शून्य छवि" और प्रतिलिपि बनाने की अनावश्यक रचना है। मैं [एफ़िन ट्रांसफॉर्मेशन] का उपयोग करके अपने समाधान को विश्वास करता हूं (http://stackoverflow.com/a/26766505/2740907) अधिक स्वच्छ और बेहतर प्रदर्शन है। –

+8

@pajus_cz, "शून्य छवि" किसी भी मामले में बनाई जाएगी, भले ही आप इसे स्वयं नहीं बना रहे हों। साथ ही, कॉपीटो सरल मेमकोपी ऑपरेशन करता है जो रैपएफ़िन द्वारा किए गए सभी जटिल संचालनों की तुलना में बहुत तेज है। – user2983637

+0

धन्यवाद! मेरे लिए लपेटने से दूसरे परिणाम तेजी से मेरे लिए। – dhiga

0

आप अपने लक्ष्य को प्राप्त करने के लिए एक सरल 2 डी फिल्टर/घुमाव के उपयोग कर सकते हैं। आपको उस कर्नेल के साथ फ़िल्टर करने की आवश्यकता होगी जिसमें ऊंचाई (वांछित_displacement_y * 2 + 1) और चौड़ाई (इच्छित_डिस्प्लेसमेंट_एक्स * 2 + 1) है।

फिर आपको प्रतिलिपि पिक्सेल स्थिति को छोड़कर कर्नेल को सभी शून्यों पर सेट करने की आवश्यकता होगी, जहां से आप प्रतिलिपि बनाना चाहते हैं। तो यदि आपका कर्नेल केंद्र (0,0) है तो आप 10 पिक्सल के विस्थापन के लिए (10,0) से 1 सेट करेंगे। filter2D में

/// Update kernel size for a normalized box filter 
    kernel_size = 1 + ind * 2; //Center pixel plus displacement diameter (=radius * 2) 
    kernel = Mat::zeros(kernel_size, kernel_size, CV_32F); 
    kernel.at<float>(ind * 2, ind) = 1.0f; // Indices are zero-based, not relative 

    /// Apply filter 
    filter2D(src, dst, ddepth , kernel, anchor, delta, BORDER_CONSTANT); 

सूचना BORDER_CONSTANT:

वेबसाइट से नमूना कोड ले लो, और निम्नलिखित के साथ बीच में गिरी कोड की जगह! अब आपको उदाहरण चलाया जाना चाहिए और चित्र को प्रत्येक 0.5 सेकंड में एक पिक्सेल द्वारा स्क्रॉल करना चाहिए। आप ड्राइंग विधियों का उपयोग करके काले पिक्सेल भी खींच सकते हैं।

यह क्यों काम करता है, Wikipedia देखें।

+0

क्रिएटिव उत्तर, लेकिन सीपीयू गहन। इसके बजाए शिफ्ट विधि का प्रयोग करें। – TimZaman

4

यहाँ करना होगा, Zaw लिन के उत्तर के आधार पर, एक समारोह मैंने लिखा है पिक्सेल की किसी भी राशि से किसी भी दिशा में फ्रेम/छवि पारी ऐसा करने के लिए पंक्तियों या स्तंभों:

enum Direction{ 
    ShiftUp=1, ShiftRight, ShiftDown, ShiftLeft 
    }; 

cv::Mat shiftFrame(cv::Mat frame, int pixels, Direction direction) 
{ 
    //create a same sized temporary Mat with all the pixels flagged as invalid (-1) 
    cv::Mat temp = cv::Mat::zeros(frame.size(), frame.type()); 

    switch (direction) 
    { 
    case(ShiftUp) : 
     frame(cv::Rect(0, pixels, frame.cols, frame.rows - pixels)).copyTo(temp(cv::Rect(0, 0, temp.cols, temp.rows - pixels))); 
     break; 
    case(ShiftRight) : 
     frame(cv::Rect(0, 0, frame.cols - pixels, frame.rows)).copyTo(temp(cv::Rect(pixels, 0, frame.cols - pixels, frame.rows))); 
     break; 
    case(ShiftDown) : 
     frame(cv::Rect(0, 0, frame.cols, frame.rows - pixels)).copyTo(temp(cv::Rect(0, pixels, frame.cols, frame.rows - pixels))); 
     break; 
    case(ShiftLeft) : 
     frame(cv::Rect(pixels, 0, frame.cols - pixels, frame.rows)).copyTo(temp(cv::Rect(0, 0, frame.cols - pixels, frame.rows))); 
     break; 
    default: 
     std::cout << "Shift direction is not set properly" << std::endl; 
    } 

    return temp; 
} 
26

आप बस affine परिवर्तन अनुवाद मैट्रिक्स (जो poi स्थानांतरण के लिए उपयोग कर सकते हैं मूल रूप से nts)। उचित परिवर्तन मैट्रिक्स के साथ cv::warpAffine() चाल करेगा।

TranslationMatrix [1,0,tx ; 0,1,ty]

जहां: tx छवि एक्स अक्ष में बदलाव है, Ty छवि y अक्ष में बदलाव है, छवि में हर एक पिक्सेल ऐसे ही स्थानांतरित कर दिया जाएगा।

आप इस फ़ंक्शन का उपयोग कर सकते हैं जो अनुवाद मैट्रिक्स देता है।(यह शायद आपके लिए अनावश्यक है) लेकिन यह छवि को offsetx और offsety पैरामीटर के आधार पर स्थानांतरित कर देगा।

Mat translateImg(Mat &img, int offsetx, int offsety){ 
    Mat trans_mat = (Mat_<double>(2,3) << 1, 0, offsetx, 0, 1, offsety); 
    warpAffine(img,img,trans_mat,img.size()); 
    return trans_mat; 
} 

आपके मामले में - आप छवि 10 पिक्सल अप शिफ्ट करना चाहते हैं, तो आप फोन:

translateImg(image,0,-10); 

और फिर अपनी छवि के रूप में आप की इच्छा स्थानांतरित किया जाएगा।

+0

क्या आप बता सकते हैं कि 'Mat_ (2,3) << 1' क्या कथन है? – locke14

+1

यह सिर्फ 'Mat_ (2,3) << 1' नहीं है। यह पूरी अभिव्यक्ति है: 'Mat_ (2,3) << 1, 0, ऑफ़सेट, 0, 1, ऑफ़सेट 'जो मैट्रिक्स में मान डालती है। तो 'पंक्ति_मैट'' में मान पहली पंक्ति में '1,0, ऑफसेट x' और दूसरी पंक्ति में' 0, 1, ऑफसेट 'होगा। जैसा कि मूल पोस्ट में मैट्रिक्स 'एम' के रूप में दिखाया गया है। –

+1

क्रिएटिव उत्तर, लेकिन अन्य समाधानों की तुलना में सीपीयू गहन। – TimZaman

1

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

using namespace cv; 
//and whatever header 'abs' requires... 

Mat offsetImageWithPadding(const Mat& originalImage, int offsetX, int offsetY, Scalar backgroundColour){ 
     cv::Mat padded = Mat(originalImage.rows + 2 * abs(offsetY), originalImage.cols + 2 * abs(offsetX), CV_8UC3, backgroundColour); 
     originalImage.copyTo(padded(Rect(abs(offsetX), abs(offsetY), originalImage.cols, originalImage.rows))); 
     return Mat(padded,Rect(abs(offsetX) + offsetX, abs(offsetY) + offsetY, originalImage.cols, originalImage.rows)); 
} 

//example use with black borders along the right hand side and top: 
Mat offsetImage = offsetImageWithPadding(originalImage, -10, 6, Scalar(0,0,0)); 

यह मेरी अपनी काम कर कोड से लिया है, लेकिन कुछ चर, बदल अगर यह नहीं करता है टी संकलन, बहुत संभावना है कि बस एक छोटी सी चीज बदलने की जरूरत है - लेकिन आपको विचार फिर से मिलता है। abs फ़ंक्शन ...

0

मैंने पहली बार pajus_cz's answer के साथ प्रयास किया, लेकिन यह अभ्यास में काफी धीमी थी। इसके अलावा, मैं एक अस्थायी प्रतिलिपि बनाने के लिए खर्च कर सकते हैं नहीं है, इसलिए मैं इस के साथ आया था:

void translateY(cv::Mat& image, int yOffset) 
{ 
    int validHeight = std::max(image.rows - abs(yOffset), 0); 
    int firstSourceRow = std::max(-yOffset, 0); 
    int firstDestinationRow = std::max(yOffset, 0); 

    memmove(image.ptr(firstDestinationRow), 
      image.ptr(firstSourceRow), 
      validHeight * image.step); 
} 

यह तेजी से warpAffine आधारित समाधान की तुलना में परिमाण के आदेश। (लेकिन निश्चित रूप से यह आपके मामले में पूरी तरह से अप्रासंगिक हो सकता है।)

2

वहाँ OpenCV के साथ सीधे यह कार्रवाई करने के लिए एक समारोह है?

http://code.opencv.org/issues/2299

या आप क्या करेंगे इस

cv::Mat out = cv::Mat::zeros(frame.size(), frame.type()); 
    frame(cv::Rect(0,10, 
    frame.cols,frame.rows-10)).copyTo(out(cv::Rect(0,0,frame.cols,frame.rows-10))); 

कोड केवल ऊपर (बाईं ओर, और शीर्ष करने के लिए) एक तरफ शिफ्ट करने के लिए इस्तेमाल किया जा सकता। नीचे कोड उपरोक्त कोड का विस्तारित संस्करण है जिसका उपयोग प्रत्येक दिशा में स्थानांतरित करने के लिए किया जा सकता है।

int shiftCol = 10; 
int shiftRow = 10; 

Rect source = cv::Rect(max(0,-shiftCol),max(0,-shiftRow), frame.cols-abs(shiftCol),frame.rows-abs(shiftRow)); 

Rect target = cv::Rect(max(0,shiftCol),max(0,shiftRow),frame.cols-abs(shiftCol),frame.rows-abs(shiftRow)); 

frame(source).copyTo(out(target));