मैं ऐसे प्रोजेक्ट पर काम कर रहा हूं जो वेबकैम से वीडियो इनपुट लेता है और उपयोगकर्ता को गति के क्षेत्र प्रदर्शित करता है। इस परियोजना में मेरा "बीटा" प्रयास वेब कैमरा फ़ीड पुनर्प्राप्त करने के लिए जावा मीडिया फ्रेमवर्क का उपयोग करना था। कुछ उपयोगिता कार्यों के माध्यम से, जेएमएफ आसानी से वेबकैम फ्रेम को BufferedImages के रूप में लौटाता है, जिसे मैंने प्रक्रिया के लिए चारों ओर ढांचे का एक महत्वपूर्ण मात्रा बनाया है। हालांकि, मुझे जल्द ही एहसास हुआ कि जेएमएफ अब सूर्य/ओरेकल द्वारा समर्थित नहीं है, और कुछ उच्च वेबकैम संकल्प (720 पी) जेएमएफ इंटरफ़ेस के माध्यम से उपलब्ध नहीं हैं।जावा मूल इंटरफ़ेस वेबकैम फ़ीड कुशलतापूर्वक कार्यान्वित करना
मैं BufferedImages के रूप में फ़्रेम को प्रोसेस करना जारी रखना चाहता हूं, और वीडियो फ़ीड स्रोत के लिए ओपनसीवी (सी ++) का उपयोग करना चाहता हूं। ओपनसीवी के ढांचे का अकेले उपयोग करके, मैंने पाया है कि ओपनसीवी कुशलतापूर्वक हाई-डेफ वेबकैम फ्रेम लौटने और उन्हें स्क्रीन पर पेंट करने का अच्छा काम करता है।
मुझे लगा कि यह जावा में इस डेटा को खिलाने और समान दक्षता प्राप्त करने के लिए बहुत सरल होगा। मैंने इस डेटा को BufferedImage में कॉपी करने और इसे जावा पर वापस करने के लिए जेएनआई डीएलएल लिखना समाप्त कर दिया। हालांकि, मुझे लगता है कि मैं जो डेटा कॉपी कर रहा हूं वह वास्तव में प्रदर्शन में बाधा डाल रहा है। मैं 30 एफपीएस को लक्षित कर रहा हूं, लेकिन जावा बुफर्ड इमेज में ओपनसीवी द्वारा लौटाए गए चार सरणी से डेटा कॉपी करने के लिए लगभग 100 एमएससी अकेले ही लेता है। इसके बजाय, मैं लगभग 2-5 एफपीएस देख रहा हूं।
फ्रेम कैप्चर लौटने पर, ओपनसीवी एक 1 डी चार सरणी के लिए एक सूचक प्रदान करता है। यह डेटा जावा को प्रदान किया जाना चाहिए, और जाहिर है कि मेरे पास इसमें से किसी एक को कॉपी करने का समय नहीं है।
मुझे इन फ्रेम कैप्चर को BufferedImage में प्राप्त करने के लिए एक बेहतर समाधान की आवश्यकता है। कुछ समाधान मैं विचार कर रहा हूँ, जिनमें से कोई भी मुझे लगता है कि बहुत अच्छा (काफी हद तक निश्चित वे भी खराब प्रदर्शन होता है) हैं:
(1) BufferedImage ओवरराइड, और के मूल निवासी कॉल करके विभिन्न BufferedImage तरीकों से पिक्सेल डेटा वापसी DLL। (एक बार में सरणी की प्रतिलिपि बनाने के बजाय, मैं कॉलिंग कोड द्वारा अनुरोध किए गए व्यक्तिगत पिक्सल लौटाता हूं)। ध्यान दें कि कॉलिंग कोड को छवि को पेंट करने या इसे संसाधित करने के लिए आम तौर पर छवि में सभी पिक्सेल की आवश्यकता होती है, इसलिए यह व्यक्तिगत पिक्सेल-ग्रैप ऑपरेशन 2 डी फॉर-लूप में लागू किया जाएगा।
(2) BufferedImage को java.nio.ByteBuffer का उपयोग करने के लिए किसी भी तरह से ओपनसीवी द्वारा लौटाए गए चार सरणी में सीधे डेटा तक पहुंचने के लिए निर्देश दें। यह कैसे किया जाता है इस बारे में किसी भी सुझाव की सराहना करेंगे।
(3) सी ++ में सबकुछ करें और जावा भूल जाएं। खैर, हाँ, यह सबसे तार्किक समाधान की तरह लगता है, हालांकि मेरे पास इस कई महीने की परियोजना शुरू करने के लिए समय नहीं होगा।
अभी तक, मेरा जेएनआई कोड बुफर्ड इमेज को वापस करने के लिए लिखा गया है, हालांकि इस बिंदु पर मैं 1 डी चार सरणी की वापसी स्वीकार करने के लिए तैयार हूं और फिर इसे बुफर्ड इमेज में डाल दूंगा।
वैसे ... सवाल यह है कि: BufferedImage में छवि डेटा के 1 डी चार सरणी को कॉपी करने का सबसे प्रभावी तरीका क्या है?
JNIEXPORT jobject JNICALL Java_graphicanalyzer_ImageFeedOpenCV_getFrame
(JNIEnv * env, jobject jThis, jobject camera)
{
//get the memory address of the CvCapture device, the value of which is encapsulated in the camera jobject
jclass cameraClass = env->FindClass("graphicanalyzer/Camera");
jfieldID fid = env->GetFieldID(cameraClass,"pCvCapture","I");
//get the address of the CvCapture device
int a_pCvCapture = (int)env->GetIntField(camera, fid);
//get a pointer to the CvCapture device
CvCapture *capture = (CvCapture*)a_pCvCapture;
//get a frame from the CvCapture device
IplImage *frame = cvQueryFrame(capture);
//get a handle on the BufferedImage class
jclass bufferedImageClass = env->FindClass("java/awt/image/BufferedImage");
if (bufferedImageClass == NULL)
{
return NULL;
}
//get a handle on the BufferedImage(int width, int height, int imageType) constructor
jmethodID bufferedImageConstructor = env->GetMethodID(bufferedImageClass,"<init>","(III)V");
//get the field ID of BufferedImage.TYPE_INT_RGB
jfieldID imageTypeFieldID = env->GetStaticFieldID(bufferedImageClass,"TYPE_INT_RGB","I");
//get the int value from the BufferedImage.TYPE_INT_RGB field
jint imageTypeIntRGB = env->GetStaticIntField(bufferedImageClass,imageTypeFieldID);
//create a new BufferedImage
jobject ret = env->NewObject(bufferedImageClass, bufferedImageConstructor, (jint)frame->width, (jint)frame->height, imageTypeIntRGB);
//get a handle on the method BufferedImage.getRaster()
jmethodID getWritableRasterID = env->GetMethodID(bufferedImageClass, "getRaster", "()Ljava/awt/image/WritableRaster;");
//call the BufferedImage.getRaster() method
jobject writableRaster = env->CallObjectMethod(ret,getWritableRasterID);
//get a handle on the WritableRaster class
jclass writableRasterClass = env->FindClass("java/awt/image/WritableRaster");
//get a handle on the WritableRaster.setPixel(int x, int y, int[] rgb) method
jmethodID setPixelID = env->GetMethodID(writableRasterClass, "setPixel", "(II[I)V"); //void setPixel(int, int, int[])
//iterate through the frame we got above and set each pixel within the WritableRaster
jintArray rgbArray = env->NewIntArray(3);
jint rgb[3];
char *px;
for (jint x=0; x < frame->width; x++)
{
for (jint y=0; y < frame->height; y++)
{
px = frame->imageData+(frame->widthStep*y+x*frame->nChannels);
rgb[0] = abs(px[2]); // OpenCV returns BGR bit order
rgb[1] = abs(px[1]); // OpenCV returns BGR bit order
rgb[2] = abs(px[0]); // OpenCV returns BGR bit order
//copy jint array into jintArray
env->SetIntArrayRegion(rgbArray,0,3,rgb); //take values in rgb and move to rgbArray
//call setPixel() this is a copy operation
env->CallVoidMethod(writableRaster,setPixelID,x,y,rgbArray);
}
}
return ret; //return the BufferedImage
}
हालांकि ऐसा लगता है कि सीवी कैप्चर डिवाइस का पता प्राप्त करने और बुफर्ड इमेज बनाने में महत्वपूर्ण ओवरहेड है, कोड निष्पादन के एक लाइन-बाय-लाइन समय से साबित होता है कि फॉर-लूप लगभग 100 एमसीसी लेता है, जबकि शेष कोड <5 एमसीसी में निष्पादित करता है। – Jason