Project

General

Profile

BitmapToolkit Scol plugin
CameraInputOpenCV.cpp
Go to the documentation of this file.
1/*
2-----------------------------------------------------------------------------
3This source file is part of OpenSpace3D
4For the latest info, see http://www.openspace3d.com
5
6Copyright (c) 2012 I-maginer
7
8This program is free software; you can redistribute it and/or modify it under
9the terms of the GNU Lesser General Public License as published by the Free Software
10Foundation; either version 2 of the License, or (at your option) any later
11version.
12
13This program is distributed in the hope that it will be useful, but WITHOUT
14ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
16
17You should have received a copy of the GNU Lesser General Public License along with
18this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19Place - Suite 330, Boston, MA 02111-1307, USA, or go to
20http://www.gnu.org/copyleft/lesser.txt
21
22-----------------------------------------------------------------------------
23*/
24
25#include "CameraInputOpenCV.h"
26
27#include <stdexcept>
28
29#ifdef APPLE_IOS
30 #include <QGuiApplication>
31 #include <QScreen>
32#endif
33
34#ifdef ANDROID
35static cv::Size calc_optimal_camera_resolution(const char* supported, int width, int height)
36{
37 int frame_width = 0;
38 int frame_height = 0;
39
40 size_t prev_idx = 0;
41 size_t idx = 0;
42 float min_diff = FLT_MAX;
43
44 do
45 {
46 int tmp_width;
47 int tmp_height;
48
49 prev_idx = idx;
50 while ((supported[idx] != '\0') && (supported[idx] != ','))
51 idx++;
52
53 sscanf(&supported[prev_idx], "%dx%d", &tmp_width, &tmp_height);
54
55 int w_diff = width - tmp_width;
56 int h_diff = height - tmp_height;
57 if ((h_diff >= 0) && (w_diff >= 0))
58 {
59 if ((h_diff <= min_diff) && (tmp_height <= 720))
60 {
61 frame_width = tmp_width;
62 frame_height = tmp_height;
63 min_diff = h_diff;
64 }
65 }
66
67 idx++; // to skip comma symbol
68
69 } while (supported[idx - 1] != '\0');
70
71 return cv::Size(frame_width, frame_height);
72}
73#endif
74
76 : ICameraInput(index)
77{
78 mAutoUpdate = false;
79 mUpdated = false;
80 mVI = new cv::VideoCapture();
81
82#ifdef APPLE_IOS
83 mVI->set(cv::CAP_PROP_FORMAT, CV_8UC3);
84 //mVI->set(cv::CAP_PROP_CONVERT_RGB, 1);
85#endif
86
87#ifdef USE_RASPICAM
88 mPI = new raspicam::RaspiCam_Cv();
89 mPI->set(cv::CAP_PROP_FORMAT, CV_8UC3);
90 mPI->set(cv::CAP_PROP_CONVERT_RGB, 1);
91#endif
92
93 mBufferSize = cv::Size(640, 480);
94}
95
97{
98 bool ret = false;
99
100#ifdef _WIN32
101 ret = mVI->open(mIndex + cv::CAP_DSHOW);
102#else
103 ret = mVI->open(mIndex);
104#endif
105
106#ifdef USE_RASPICAM
107 if (!ret)
108 ret = mPI->open();
109#endif
110
111 if (ret)
112 {
113 // init default size (Pass the webcam in preview mode !!)
114 SetSize(mBufferSize.width, mBufferSize.height);
115 }
116
117 return ret;
118}
119
121{
122 mAutoUpdate = false;
123 if (mThread.joinable())
124 mThread.join();
125
126#ifdef USE_RASPICAM
127 mPI->release();
128#endif
129
130 mVI->release();
131}
132
134{
135 Close();
136 SAFE_DELETE(mVI);
137
138#ifdef USE_RASPICAM
139 SAFE_DELETE(mPI);
140#endif
141}
142
144{
145#ifdef USE_RASPICAM
146 if (mPI->isOpened())
147 return true;
148#endif
149 return mVI->isOpened();
150}
151
153{
154 while (mAutoUpdate)
155 {
156 double tick = (double)cv::getTickCount();
157 bool valid = false;
158#ifdef USE_RASPICAM
159 if (mPI->isOpened())
160 valid = mPI->read(mBuffer);
161 else
162#endif
163 valid = mVI->read(mBuffer);
164
165 if (valid)
166 {
167 boost::upgrade_lock< boost::shared_mutex > lock(mMutex);
168
169#ifdef APPLE_IOS
170 QScreen* screen = QGuiApplication::primaryScreen();
171 Qt::ScreenOrientation rotation = screen->orientation();
172
173 //image mirror for front view is managed by user
174 if ((rotation == Qt::LandscapeOrientation) && (mIndex == 0))
175 {
176 cv::transpose(mBuffer, mCachedFrame);
177 cv::flip(mCachedFrame, mCachedFrame, 0);
178 }
179 else if ((rotation == Qt::LandscapeOrientation) && (mIndex == 1))
180 {
181 cv::transpose(mBuffer, mCachedFrame);
182 }
183 else if ((rotation == Qt::PortraitOrientation) && (mIndex == 1))
184 {
185 cv::flip(mBuffer, mCachedFrame, 1);
186 }
187 else if ((rotation == Qt::InvertedPortraitOrientation) && (mIndex == 0))
188 {
189 cv::flip(mBuffer, mCachedFrame, -1);
190 }
191 else if ((rotation == Qt::InvertedPortraitOrientation) && (mIndex == 1))
192 {
193 cv::flip(mBuffer, mCachedFrame, 0);
194 }
195 else if ((rotation == Qt::InvertedLandscapeOrientation) && (mIndex == 0))
196 {
197 cv::transpose(mBuffer, mCachedFrame);
198 cv::flip(mCachedFrame, mCachedFrame, 1);
199 }
200 else if ((rotation == Qt::InvertedLandscapeOrientation) && (mIndex == 1))
201 {
202 cv::transpose(mBuffer, mCachedFrame);
203 cv::flip(mCachedFrame, mCachedFrame, -1);
204 }
205 else
206 {
207 if (mBuffer.rows == mCachedFrame.rows && mBuffer.cols == mCachedFrame.cols)
208 memcpy(mCachedFrame.data, mBuffer.data, mBuffer.rows * mBuffer.cols * 3);
209 else
210 mBuffer.copyTo(mCachedFrame);
211 }
212#else
213 if (!mCachedFrame.empty() && (mBuffer.rows == mCachedFrame.rows && mBuffer.cols == mCachedFrame.cols))
214 memcpy(mCachedFrame.data, mBuffer.data, mBuffer.rows * mBuffer.cols * 3);
215 else
216 mBuffer.copyTo(mCachedFrame);
217#endif
218 mUpdated = true;
219 lock.unlock();
220 }
221 else
222 {
223 boost::upgrade_lock< boost::shared_mutex > lock(mMutex);
224 mCachedFrame.release();
225 lock.unlock();
226 }
227
228 //prevent cpu burn
229 tick = ((double)cv::getTickCount() - tick) / cv::getTickFrequency();
230 boost::this_thread::sleep_for(boost::chrono::milliseconds(std::max(16 - (int)(tick * 1000), 0))); //DO not burn too much CPU
231 }
232}
233
235{
236 if (!IsOpened())
237 throw std::logic_error("Device not initialised");
238
239 boost::upgrade_lock< boost::shared_mutex > lock(mMutex);
240 if (!mUpdated || mCachedFrame.empty())
241 {
242 mUpdated = false;
243
244 lock.unlock();
245 throw std::logic_error("Device has bad pixel buffer");
246 }
247
248 mUpdated = false;
249
250 //OpenCV 2.4
251 /*
252#ifdef ANDROID
253 if (!mVI->retrieve(frame, CV_CAP_ANDROID_COLOR_FRAME_BGR) || frame.empty())
254 throw std::logic_error("frame is empty");
255#else
256 if (!mVI->retrieve(frame) || frame.empty())
257 throw std::logic_error("frame is empty");
258#endif
259 */
260
261 if (mRetrieveBuffer.rows == mCachedFrame.rows && mRetrieveBuffer.cols == mCachedFrame.cols)
262 memcpy(mRetrieveBuffer.data, mCachedFrame.data, mCachedFrame.rows * mCachedFrame.cols * 3);
263 else
264 mCachedFrame.copyTo(mRetrieveBuffer);
265
266 lock.unlock();
267 return mRetrieveBuffer;
268}
269
271{
272 if (IsOpened())
273 {
274#ifdef APPLE_IOS
275 QScreen* screen = QGuiApplication::primaryScreen();
276 if (screen->primaryOrientation() == Qt::PortraitOrientation)
277 return mBufferSize.height;
278 else
279 return mBufferSize.width;
280#else
281 return mBufferSize.width;
282#endif
283 }
284 else
285 return 0;
286}
287
289{
290 if (IsOpened())
291 {
292#ifdef APPLE_IOS
293 QScreen* screen = QGuiApplication::primaryScreen();
294 if (screen->primaryOrientation() == Qt::PortraitOrientation)
295 return mBufferSize.width;
296 else
297 return mBufferSize.height;
298#else
299 return mBufferSize.height;
300#endif
301 }
302 else
303 return 0;
304}
305
306void CameraInputOpenCV::SetSize(int width, int height)
307{
308#ifdef APPLE_IOS
309 //Iphone are too slowwwwwwww
310 QScreen* screen = QGuiApplication::primaryScreen();
311 if (screen->primaryOrientation() == Qt::PortraitOrientation)
312 {
313 int ow = width;
314 width = height;
315 height = ow;
316 }
317#endif
318
319 if (IsOpened())
320 {
321 mAutoUpdate = false;
322 mThread.join();
323
324#ifdef RPI
325 mBufferSize = cv::Size(width - (width % 320), height - (height % 240));
326#else
327 mBufferSize = cv::Size(width, height);
328#endif
329
330 if ((mBufferSize.width != 0) && (mBufferSize.height != 0))
331 {
332 try
333 {
334#ifdef USE_RASPICAM
335 if (mPI->isOpened())
336 {
337 mPI->release();
338 mPI->set(cv::CAP_PROP_FRAME_WIDTH, mBufferSize.width);
339 mPI->set(cv::CAP_PROP_FRAME_HEIGHT, mBufferSize.height);
340 mPI->open();
341 }
342 else
343 {
344#endif
345 mVI->set(cv::CAP_PROP_FRAME_WIDTH, mBufferSize.width);
346 mVI->set(cv::CAP_PROP_FRAME_HEIGHT, mBufferSize.height);
347
348#ifdef USE_RASPICAM
349 }
350#endif
351 }
352 catch (std::exception &)
353 {
354 mBufferSize = cv::Size(640, 480);
355 }
356 }
357 else
358 {
359 mBufferSize = cv::Size(640, 480);
360 }
361
362 //get real setted size
363#ifdef USE_RASPICAM
364 if (mPI->isOpened())
365 {
366 mBufferSize.width = mPI->get(cv::CAP_PROP_FRAME_WIDTH);
367 mBufferSize.height = mPI->get(cv::CAP_PROP_FRAME_HEIGHT);
368 }
369 else
370 {
371#endif
372 mBufferSize.width = mVI->get(cv::CAP_PROP_FRAME_WIDTH);
373 mBufferSize.height = mVI->get(cv::CAP_PROP_FRAME_HEIGHT);
374
375#ifdef USE_RASPICAM
376 }
377#endif
378
379 MMechostr(MSKRUNTIME, "CameraInputOpenCV::SetSize: Creating output buffer with size %dx%d\n", mBufferSize.width, mBufferSize.height);
380#ifdef APPLE_IOS
381 mBuffer = cv::Mat(mBufferSize.width, mBufferSize.height, CV_8UC3);
382#else
383 mBuffer = cv::Mat(mBufferSize.height, mBufferSize.width, CV_8UC3);
384#endif
385
386 mAutoUpdate = true;
387 mThread = boost::thread(boost::bind(&CameraInputOpenCV::UpdateThread, this));
388 }
389 else
390 {
391 mBufferSize = cv::Size(width, height);
392#ifdef APPLE_IOS
393 mBuffer = cv::Mat(mBufferSize.width, mBufferSize.height, CV_8UC3);
394#else
395 mBuffer = cv::Mat(mBufferSize.height, mBufferSize.width, CV_8UC3);
396#endif
397 }
398
399 mCachedFrame.release();
400 mUpdated = false;
401}
402
404{
405 if (!IsOpened())
406 return false;
407
408 cv::Mat frame = UpdateImage();
409 if (frame.empty())
410 return false;
411
412 if (!cv::imwrite(path, frame))
413 return false;
414
415 MMechostr(MSKRUNTIME, ">> Frame written to : %s\n", path.c_str());
416 return true;
417}
virtual cv::Mat UpdateImage()
virtual void SetSize(int width, int height)
virtual bool Initialize()
virtual bool TakeSnapshot(std::string path)
Interface for camera management. Concrete classes are written for Windows, Android and OpenCV native ...