Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
O
opencv
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
opencv
Commits
31e77a3b
Commit
31e77a3b
authored
Apr 18, 2011
by
Andrey Kamaev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Android native camera: added BGR output format; added methods to configure output frame size.
parent
1965b297
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
275 additions
and
171 deletions
+275
-171
highgui_c.h
modules/highgui/include/opencv2/highgui/highgui_c.h
+2
-3
cap_android.cpp
modules/highgui/src/cap_android.cpp
+273
-168
No files found.
modules/highgui/include/opencv2/highgui/highgui_c.h
View file @
31e77a3b
...
...
@@ -392,9 +392,8 @@ enum
//supported by Android camera output formats
enum
{
CV_CAP_ANDROID_COLOR_FRAME
=
1
,
//TODO: check RGB or BGR?
CV_CAP_ANDROID_GREY_FRAME
=
0
,
CV_CAP_ANDROID_YUV_FRAME
=
2
CV_CAP_ANDROID_COLOR_FRAME
=
0
,
//BGR
CV_CAP_ANDROID_GREY_FRAME
=
1
//Y
};
/* retrieve or set capture properties */
...
...
modules/highgui/src/cap_android.cpp
View file @
31e77a3b
/*M///////////////////////////////////////////////////////////////////////////////////////
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
...
...
@@ -58,7 +58,7 @@ class HighguiAndroidCameraActivity;
class
CvCapture_Android
:
public
CvCapture
{
public
:
CvCapture_Android
();
CvCapture_Android
(
int
);
virtual
~
CvCapture_Android
();
virtual
double
getProperty
(
int
propIdx
);
...
...
@@ -81,66 +81,74 @@ protected:
CameraActivity
*
m_activity
;
//raw from camera
int
m_width
;
int
m_height
;
unsigned
char
*
m_frameYUV420i
;
unsigned
char
*
m_frameYUV420inext
;
void
setFrame
(
const
void
*
buffer
,
int
bufferSize
);
private
:
bool
m_isOpened
;
bool
m_CameraParamsChanged
;
//frames counter for statistics
int
m_framesGrabbed
;
OutputMap
*
m_frameYUV
;
OutputMap
*
m_frameYUVnext
;
//cached converted frames
OutputMap
m_frameGray
;
OutputMap
m_frameColor
;
bool
m_hasGray
;
bool
m_hasColor
;
//synchronization
pthread_mutex_t
m_nextFrameMutex
;
pthread_cond_t
m_nextFrameCond
;
volatile
bool
m_waitingNextFrame
;
int
m_framesGrabbed
;
friend
class
HighguiAndroidCameraActivity
;
void
prepareCacheForYUV420i
(
int
width
,
int
height
)
;
static
bool
convertYUV420i2Grey
(
int
width
,
int
height
,
const
unsigned
char
*
yuv
,
cv
::
Mat
&
resmat
);
static
bool
convertYUV420i2BGR888
(
int
width
,
int
height
,
const
unsigned
char
*
yuv
,
cv
::
Mat
&
resmat
)
;
void
onFrame
(
const
void
*
buffer
,
int
bufferSize
);
void
convertBufferToYUV
(
const
void
*
buffer
,
int
size
,
int
width
,
int
height
);
static
bool
convertYUVToGrey
(
const
cv
::
Mat
&
yuv
,
cv
::
Mat
&
resmat
);
static
bool
convertYUVToColor
(
const
cv
::
Mat
&
yuv
,
cv
::
Mat
&
resmat
);
friend
class
HighguiAndroidCameraActivity
;
};
class
HighguiAndroidCameraActivity
:
public
CameraActivity
{
public
:
public
:
HighguiAndroidCameraActivity
(
CvCapture_Android
*
capture
)
{
m_capture
=
capture
;
m_framesReceived
=
0
;
m_capture
=
capture
;
m_framesReceived
=
0
;
}
virtual
bool
onFrameBuffer
(
void
*
buffer
,
int
bufferSize
)
{
LOGD
(
"buffer addr:%p size:%d"
,
buffer
,
bufferSize
);
if
(
isConnected
()
&&
buffer
!=
0
&&
bufferSize
>
0
)
{
m_framesReceived
++
;
if
(
m_capture
->
m_waitingNextFrame
)
{
m_capture
->
onFrame
(
buffer
,
bufferSize
);
pthread_mutex_lock
(
&
m_capture
->
m_nextFrameMutex
);
m_capture
->
m_waitingNextFrame
=
false
;
//set flag that no more frames required at this moment
pthread_cond_broadcast
(
&
m_capture
->
m_nextFrameCond
);
pthread_mutex_unlock
(
&
m_capture
->
m_nextFrameMutex
);
}
return
true
;
}
return
false
;
if
(
isConnected
()
&&
buffer
!=
0
&&
bufferSize
>
0
)
{
m_framesReceived
++
;
if
(
m_capture
->
m_waitingNextFrame
)
{
m_capture
->
setFrame
(
buffer
,
bufferSize
);
pthread_mutex_lock
(
&
m_capture
->
m_nextFrameMutex
);
m_capture
->
m_waitingNextFrame
=
false
;
//set flag that no more frames required at this moment
pthread_cond_broadcast
(
&
m_capture
->
m_nextFrameCond
);
pthread_mutex_unlock
(
&
m_capture
->
m_nextFrameMutex
);
}
return
true
;
}
return
false
;
}
void
LogFramesRate
()
{
LOGI
(
"FRAMES received: %d grabbed: %d"
,
m_framesReceived
,
m_capture
->
m_framesGrabbed
);
LOGI
(
"FRAMES received: %d grabbed: %d"
,
m_framesReceived
,
m_capture
->
m_framesGrabbed
);
}
private
:
private
:
CvCapture_Android
*
m_capture
;
int
m_framesReceived
;
};
...
...
@@ -154,195 +162,292 @@ IplImage* CvCapture_Android::OutputMap::getIplImagePtr()
return
&
iplHeader
;
}
bool
CvCapture_Android
::
isOpened
()
const
CvCapture_Android
::
CvCapture_Android
(
int
cameraId
)
{
return
m_isOpened
;
//defaults
m_width
=
0
;
m_height
=
0
;
m_activity
=
0
;
m_isOpened
=
false
;
m_frameYUV420i
=
0
;
m_frameYUV420inext
=
0
;
m_hasGray
=
false
;
m_hasColor
=
false
;
m_waitingNextFrame
=
false
;
m_framesGrabbed
=
0
;
m_CameraParamsChanged
=
false
;
//try connect to camera
m_activity
=
new
HighguiAndroidCameraActivity
(
this
);
if
(
m_activity
==
0
)
return
;
pthread_mutex_init
(
&
m_nextFrameMutex
,
NULL
);
pthread_cond_init
(
&
m_nextFrameCond
,
NULL
);
CameraActivity
::
ErrorCode
errcode
=
m_activity
->
connect
(
cameraId
);
if
(
errcode
==
CameraActivity
::
NO_ERROR
)
m_isOpened
=
true
;
else
{
LOGE
(
"Native_camera returned opening error: %d"
,
errcode
);
delete
m_activity
;
m_activity
=
0
;
}
}
CvCapture_Android
::
CvCapture_Android
()
bool
CvCapture_Android
::
isOpened
()
const
{
//defaults
m_activity
=
0
;
m_isOpened
=
false
;
m_frameYUV
=
0
;
m_frameYUVnext
=
0
;
m_hasGray
=
false
;
m_hasColor
=
false
;
m_waitingNextFrame
=
false
;
m_framesGrabbed
=
0
;
//try connect to camera
m_activity
=
new
HighguiAndroidCameraActivity
(
this
);
if
(
m_activity
==
0
)
return
;
pthread_mutex_init
(
&
m_nextFrameMutex
,
NULL
);
pthread_cond_init
(
&
m_nextFrameCond
,
NULL
);
CameraActivity
::
ErrorCode
errcode
=
m_activity
->
connect
();
if
(
errcode
==
CameraActivity
::
NO_ERROR
)
{
m_isOpened
=
true
;
m_frameYUV
=
new
OutputMap
();
m_frameYUVnext
=
new
OutputMap
();
}
else
{
LOGE
(
"Native_camera returned opening error: %d"
,
errcode
);
delete
m_activity
;
m_activity
=
0
;
}
return
m_isOpened
;
}
CvCapture_Android
::~
CvCapture_Android
()
{
if
(
m_activity
)
{
((
HighguiAndroidCameraActivity
*
)
m_activity
)
->
LogFramesRate
();
//m_activity->disconnect() will be automatically called inside destructor;
delete
m_activity
;
delete
m_frameYUV
;
delete
m_frameYUV
next
;
m_activity
=
0
;
m_frameYUV
=
0
;
m_frameYUV
next
=
0
;
pthread_mutex_destroy
(
&
m_nextFrameMutex
);
pthread_cond_destroy
(
&
m_nextFrameCond
);
}
if
(
m_activity
)
{
((
HighguiAndroidCameraActivity
*
)
m_activity
)
->
LogFramesRate
();
//m_activity->disconnect() will be automatically called inside destructor;
delete
m_activity
;
delete
m_frameYUV420i
;
delete
m_frameYUV420i
next
;
m_activity
=
0
;
m_frameYUV420i
=
0
;
m_frameYUV420i
next
=
0
;
pthread_mutex_destroy
(
&
m_nextFrameMutex
);
pthread_cond_destroy
(
&
m_nextFrameCond
);
}
}
double
CvCapture_Android
::
getProperty
(
int
propIdx
)
{
switch
(
propIdx
)
{
switch
(
propIdx
)
{
case
CV_CAP_PROP_FRAME_WIDTH
:
return
(
double
)
CameraActivity
::
getFrameWidth
();
return
(
double
)
m_activity
->
getFrameWidth
();
case
CV_CAP_PROP_FRAME_HEIGHT
:
return
(
double
)
CameraActivity
::
getFrameHeight
();
return
(
double
)
m_activity
->
getFrameHeight
();
default
:
CV_Error
(
CV_StsError
,
"Failed attempt to GET unsupported camera property."
);
break
;
}
return
-
1.0
;
CV_Error
(
CV_StsOutOfRange
,
"Failed attempt to GET unsupported camera property."
);
break
;
}
return
-
1.0
;
}
bool
CvCapture_Android
::
setProperty
(
int
propIdx
,
double
propValue
)
{
bool
res
=
false
;
if
(
isOpened
()
)
{
switch
(
propIdx
)
bool
res
=
false
;
if
(
isOpened
()
)
{
default
:
CV_Error
(
CV_StsError
,
"Failed attempt to SET unsupported camera property."
);
break
;
switch
(
propIdx
)
{
case
CV_CAP_PROP_FRAME_WIDTH
:
m_activity
->
setProperty
(
ANDROID_CAMERA_PROPERTY_FRAMEWIDTH
,
propValue
);
break
;
case
CV_CAP_PROP_FRAME_HEIGHT
:
m_activity
->
setProperty
(
ANDROID_CAMERA_PROPERTY_FRAMEHEIGHT
,
propValue
);
break
;
default
:
CV_Error
(
CV_StsOutOfRange
,
"Failed attempt to SET unsupported camera property."
);
break
;
}
m_CameraParamsChanged
=
true
;
}
}
return
res
;
return
res
;
}
bool
CvCapture_Android
::
grabFrame
()
{
if
(
!
isOpened
()
)
return
false
;
pthread_mutex_lock
(
&
m_nextFrameMutex
);
m_waitingNextFrame
=
true
;
pthread_cond_wait
(
&
m_nextFrameCond
,
&
m_nextFrameMutex
);
pthread_mutex_unlock
(
&
m_nextFrameMutex
);
m_framesGrabbed
++
;
return
true
;
if
(
!
isOpened
()
)
return
false
;
pthread_mutex_lock
(
&
m_nextFrameMutex
);
if
(
m_CameraParamsChanged
)
{
m_activity
->
applyProperties
();
m_CameraParamsChanged
=
false
;
}
m_waitingNextFrame
=
true
;
pthread_cond_wait
(
&
m_nextFrameCond
,
&
m_nextFrameMutex
);
pthread_mutex_unlock
(
&
m_nextFrameMutex
);
m_framesGrabbed
++
;
return
true
;
}
IplImage
*
CvCapture_Android
::
retrieveFrame
(
int
outputType
)
{
IplImage
*
image
=
0
;
if
(
0
!=
m_frameYUV420i
)
{
switch
(
outputType
)
{
case
CV_CAP_ANDROID_COLOR_FRAME
:
if
(
!
m_hasColor
)
if
(
!
(
m_hasColor
=
convertYUV420i2BGR888
(
m_width
,
m_height
,
m_frameYUV420i
,
m_frameColor
.
mat
)))
return
0
;
image
=
m_frameColor
.
getIplImagePtr
();
break
;
case
CV_CAP_ANDROID_GREY_FRAME
:
if
(
!
m_hasGray
)
if
(
!
(
m_hasGray
=
convertYUV420i2Grey
(
m_width
,
m_height
,
m_frameYUV420i
,
m_frameGray
.
mat
)))
return
0
;
image
=
m_frameGray
.
getIplImagePtr
();
break
;
default
:
LOGE
(
"Unsupported frame output format: %d"
,
outputType
);
CV_Error
(
CV_StsOutOfRange
,
"Output frame format is not supported."
);
image
=
0
;
break
;
}
}
return
image
;
}
void
CvCapture_Android
::
on
Frame
(
const
void
*
buffer
,
int
bufferSize
)
void
CvCapture_Android
::
set
Frame
(
const
void
*
buffer
,
int
bufferSize
)
{
LOGD
(
"Buffer available: %p + %d"
,
buffer
,
bufferSize
);
int
width
=
m_activity
->
getFrameWidth
();
int
height
=
m_activity
->
getFrameHeight
();
int
expectedSize
=
(
width
*
height
*
3
)
>>
1
;
if
(
expectedSize
!=
bufferSize
)
{
LOGE
(
"ERROR reading YUV420i buffer: width=%d, height=%d, size=%d, receivedSize=%d"
,
width
,
height
,
expectedSize
,
bufferSize
);
return
;
}
//allocate memery if needed
prepareCacheForYUV420i
(
width
,
height
);
convertBufferToYUV
(
buffer
,
bufferSize
,
CameraActivity
::
getFrameWidth
(),
CameraActivity
::
getFrameHeight
());
//copy data
memcpy
(
m_frameYUV420inext
,
buffer
,
bufferSize
);
//swap current and new frames
OutputMap
*
tmp
=
m_frameYUV
;
m_frameYUV
=
m_frameYUV
next
;
m_frameYUV
next
=
tmp
;
//swap current and new frames
unsigned
char
*
tmp
=
m_frameYUV420i
;
m_frameYUV420i
=
m_frameYUV420i
next
;
m_frameYUV420i
next
=
tmp
;
//discard cached frames
m_hasGray
=
false
;
m_hasColor
=
false
;
//discard cached frames
m_hasGray
=
false
;
m_hasColor
=
false
;
}
IplImage
*
CvCapture_Android
::
retrieveFrame
(
int
outputType
)
void
CvCapture_Android
::
prepareCacheForYUV420i
(
int
width
,
int
height
)
{
IplImage
*
image
=
0
;
if
(
0
!=
m_frameYUV
&&
!
m_frameYUV
->
mat
.
empty
())
{
switch
(
outputType
)
if
(
width
!=
m_width
||
height
!=
m_height
)
{
case
CV_CAP_ANDROID_YUV_FRAME
:
image
=
m_frameYUV
->
getIplImagePtr
();
break
;
case
CV_CAP_ANDROID_GREY_FRAME
:
if
(
!
m_hasGray
)
if
(
!
(
m_hasGray
=
convertYUVToGrey
(
m_frameYUV
->
mat
,
m_frameGray
.
mat
)))
image
=
0
;
image
=
m_frameGray
.
getIplImagePtr
();
break
;
case
CV_CAP_ANDROID_COLOR_FRAME
:
if
(
!
m_hasColor
)
if
(
!
(
m_hasColor
=
convertYUVToColor
(
m_frameYUV
->
mat
,
m_frameColor
.
mat
)))
image
=
0
;
image
=
m_frameColor
.
getIplImagePtr
();
break
;
default
:
LOGE
(
"Unsupported frame output format: %d"
,
outputType
);
image
=
0
;
break
;
m_width
=
width
;
m_height
=
height
;
unsigned
char
*
tmp
=
m_frameYUV420inext
;
m_frameYUV420inext
=
new
unsigned
char
[
width
*
height
*
3
/
2
];
delete
[]
tmp
;
tmp
=
m_frameYUV420i
;
m_frameYUV420i
=
new
unsigned
char
[
width
*
height
*
3
/
2
];
delete
[]
tmp
;
}
}
return
image
;
}
void
CvCapture_Android
::
convertBufferToYUV
(
const
void
*
buffer
,
int
size
,
int
width
,
int
height
)
inline
unsigned
char
clamp
(
int
value
)
{
cv
::
Size
buffSize
(
width
,
height
+
(
height
/
2
));
if
(
buffSize
.
area
()
!=
size
)
{
LOGE
(
"ERROR convertBufferToYuv_Mat: width=%d, height=%d, buffSize=%d x %d, buffSize.area()=%d, size=%d"
,
width
,
height
,
buffSize
.
width
,
buffSize
.
height
,
buffSize
.
area
(),
size
);
return
;
}
m_frameYUVnext
->
mat
.
create
(
buffSize
,
CV_8UC1
);
uchar
*
matBuff
=
m_frameYUVnext
->
mat
.
ptr
<
uchar
>
(
0
);
memcpy
(
matBuff
,
buffer
,
size
);
if
(
value
<=
0
)
return
0
;
if
(
value
>=
255
)
return
(
unsigned
char
)
255
;
return
(
unsigned
char
)
value
;
}
bool
CvCapture_Android
::
convertYUVToGrey
(
const
cv
::
Mat
&
yuv
,
cv
::
Mat
&
resmat
)
{
if
(
yuv
.
empty
())
return
false
;
resmat
=
yuv
(
cv
::
Range
(
0
,
yuv
.
rows
*
(
2.0
f
/
3
)),
cv
::
Range
::
all
());
bool
CvCapture_Android
::
convertYUV420i2Grey
(
int
width
,
int
height
,
const
unsigned
char
*
yuv
,
cv
::
Mat
&
resmat
)
{
if
(
yuv
==
0
)
return
false
;
return
!
resmat
.
empty
();
resmat
.
create
(
width
,
height
,
CV_8UC1
);
unsigned
char
*
matBuff
=
resmat
.
ptr
<
unsigned
char
>
(
0
);
memcpy
(
matBuff
,
yuv
,
width
*
height
);
return
!
resmat
.
empty
();
}
bool
CvCapture_Android
::
convertYUV
ToColor
(
const
cv
::
Mat
&
yuv
,
cv
::
Mat
&
resmat
)
bool
CvCapture_Android
::
convertYUV
420i2BGR888
(
int
width
,
int
height
,
const
unsigned
char
*
yuv
,
cv
::
Mat
&
resmat
)
{
if
(
yuv
.
empty
())
return
false
;
if
(
yuv
==
0
)
return
false
;
CV_Assert
(
width
%
2
==
0
&&
height
%
2
==
0
);
resmat
.
create
(
height
,
width
,
CV_8UC3
);
unsigned
char
*
y1
=
(
unsigned
char
*
)
yuv
;
unsigned
char
*
uv
=
y1
+
width
*
height
;
//B = 1.164(Y - 16) + 2.018(U - 128)
//G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128)
//R = 1.164(Y - 16) + 1.596(V - 128)
for
(
int
j
=
0
;
j
<
height
;
j
+=
2
,
y1
+=
width
*
2
,
uv
+=
width
)
{
unsigned
char
*
row1
=
resmat
.
ptr
<
unsigned
char
>
(
j
);
unsigned
char
*
row2
=
resmat
.
ptr
<
unsigned
char
>
(
j
+
1
);
unsigned
char
*
y2
=
y1
+
width
;
for
(
int
i
=
0
;
i
<
width
;
i
+=
2
,
row1
+=
6
,
row2
+=
6
)
{
// unsigned char cr = uv[i];
// unsigned char cb = uv[i+1];
// row1[0] = y1[i];
// row1[1] = cr;
// row1[2] = cb;
// row1[3] = y1[i+1];
// row1[4] = cr;
// row1[5] = cb;
// row2[0] = y2[i];
// row2[1] = cr;
// row2[2] = cb;
// row2[3] = y2[i+1];
// row2[4] = cr;
// row2[5] = cb;
int
cr
=
uv
[
i
]
-
128
;
int
cb
=
uv
[
i
+
1
]
-
128
;
int
ruv
=
409
*
cr
+
128
;
int
guv
=
128
-
100
*
cb
-
208
*
cr
;
int
buv
=
516
*
cb
+
128
;
int
y00
=
(
y1
[
i
]
-
16
)
*
298
;
row1
[
0
]
=
clamp
((
y00
+
buv
)
>>
8
);
row1
[
1
]
=
clamp
((
y00
+
guv
)
>>
8
);
row1
[
2
]
=
clamp
((
y00
+
ruv
)
>>
8
);
int
y01
=
(
y1
[
i
+
1
]
-
16
)
*
298
;
row1
[
3
]
=
clamp
((
y01
+
buv
)
>>
8
);
row1
[
4
]
=
clamp
((
y01
+
guv
)
>>
8
);
row1
[
5
]
=
clamp
((
y01
+
ruv
)
>>
8
);
int
y10
=
(
y2
[
i
]
-
16
)
*
298
;
row2
[
0
]
=
clamp
((
y10
+
buv
)
>>
8
);
row2
[
1
]
=
clamp
((
y10
+
guv
)
>>
8
);
row2
[
2
]
=
clamp
((
y10
+
ruv
)
>>
8
);
int
y11
=
(
y2
[
i
+
1
]
-
16
)
*
298
;
row2
[
3
]
=
clamp
((
y11
+
buv
)
>>
8
);
row2
[
4
]
=
clamp
((
y11
+
guv
)
>>
8
);
row2
[
5
]
=
clamp
((
y11
+
ruv
)
>>
8
);
}
}
cv
::
cvtColor
(
yuv
,
resmat
,
CV_YUV2RGB
);
return
!
resmat
.
empty
();
return
!
resmat
.
empty
();
}
CvCapture
*
cvCreateCameraCapture_Android
(
int
/*index*/
)
CvCapture
*
cvCreateCameraCapture_Android
(
int
cameraId
)
{
CvCapture_Android
*
capture
=
new
CvCapture_Android
();
CvCapture_Android
*
capture
=
new
CvCapture_Android
(
cameraId
);
if
(
capture
->
isOpened
()
)
return
capture
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment