Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
J
jp4-canvas
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Elphel
jp4-canvas
Commits
3b57e648
Commit
3b57e648
authored
Jul 07, 2015
by
Oleg Dzhimiev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
1. fixed borders in demosaicing 2. added RGB -> YCbCr*saturation (default=2) -> RGB
parent
2f6bd3df
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
103 additions
and
46 deletions
+103
-46
README.md
README.md
+0
-1
jp4-canvas.js
jp4-canvas.js
+103
-45
No files found.
README.md
View file @
3b57e648
...
...
@@ -3,7 +3,6 @@
A template
<br/>
Convert JP4/JP46 image files (
\*
.jp4/
\*
.jp46) into human perceivable format.
<br/>
This includes reordering within JPEG blocks and demosaicing (bilinear interpolation).
<br/>
The result looks a bit pale - saturation is not calculated.
Files in JPEG format are left untouched.
## Usage
Replace
<i>
test.jp4
</i>
...
...
jp4-canvas.js
View file @
3b57e648
...
...
@@ -11,6 +11,14 @@ var COLOR_MODE = 0;
var
IS_JP4
=
false
;
var
IS_JP46
=
false
;
//GRBG
var
bayerMosaic
=
[
"Gr"
,
"R"
,
"B"
,
"Gb"
];
var
SATURATION
=
2.0
;
$
(
function
(){
initCanvas
();
});
...
...
@@ -59,9 +67,11 @@ function redraw(){
$
(
this
).
draw
({
fn
:
function
(
ctx
){
if
(
IS_JP4
||
IS_JP46
){
pixelBlocksReorder
(
ctx
);
demosaic_bilinear
(
ctx
);
}
pixelBlocksReorder
(
ctx
);
demosaic_bilinear
(
ctx
);
//convert to YCbCr to apply some saturation
saturation
(
ctx
);
}
}
});
}
...
...
@@ -97,44 +107,42 @@ function pixelBlocksReorder(ctx){
// horizontal step = 16 pixels
for
(
xb
=
0
;
xb
<
(
width
>>
4
);
xb
++
)
{
if
(
IS_JP4
)
{
// 32x8 block reorder into 16x16
for
(
nb
=
0
;
nb
<
4
;
nb
++
)
{
xbyr
=
nb
&
1
;
// horizontal odd-even
// 32x8 block reorder into 16x16
for
(
nb
=
0
;
nb
<
4
;
nb
++
)
{
xbyr
=
nb
&
1
;
// horizontal odd-even
ybyr
=
(
nb
>>
1
)
&
1
;
// vertical odd-even
for
(
y
=
0
;
y
<
8
;
y
++
)
{
// xb < half image -> 1st line of 32x8
// xb >= half image -> 2nd line of 32x8
//offset=(((yb<<4)+y)*width)+(nb<<3)+((xb>=(width>>5))?(((xb<<5)-width)+(width<<3)):(xb<<5));
offset
=
(((
yb
<<
4
)
+
y
)
*
width
)
+
(
nb
<<
3
)
+
(
xb
<<
5
)
+
((
xb
>=
(
width
>>
5
))?((
width
<<
3
)
-
width
):
0
);
for
(
x
=
0
;
x
<
8
;
x
++
)
{
macroblock
[(
y
<<
1
)
|
ybyr
][(
x
<<
1
)
|
xbyr
]
=
iPixels
[
4
*
(
offset
+
x
)];
}
}
}
}
if
(
IS_JP46
)
{
// xb >= half image -> 2nd line of 32x8
//offset=(((yb<<4)+y)*width)+(nb<<3)+((xb>=(width>>5))?(((xb<<5)-width)+(width<<3)):(xb<<5));
offset
=
(((
yb
<<
4
)
+
y
)
*
width
)
+
(
nb
<<
3
)
+
(
xb
<<
5
)
+
((
xb
>=
(
width
>>
5
))?((
width
<<
3
)
-
width
):
0
);
for
(
x
=
0
;
x
<
8
;
x
++
)
{
macroblock
[(
y
<<
1
)
|
ybyr
][(
x
<<
1
)
|
xbyr
]
=
iPixels
[
4
*
(
offset
+
x
)];
}
}
}
}
if
(
IS_JP46
)
{
for
(
y
=
0
;
y
<
16
;
y
++
)
{
offset
=
((
yb
<<
4
)
+
y
)
*
width
+
(
xb
<<
4
);
for
(
x
=
0
;
x
<
16
;
x
++
)
{
macroblock
[((
y
<<
1
)
&
0xe
)
|
((
y
>>
3
)
&
0x1
)][((
x
<<
1
)
&
0xe
)
|
((
x
>>
3
)
&
0x1
)]
=
iPixels
[
4
*
(
offset
+
x
)];
}
}
}
/* apply gammas here */
// ... or not
for
(
y
=
0
;
y
<
16
;
y
++
)
{
offset
=
width
*
((
yb
<<
4
)
+
y
)
+
(
xb
<<
4
);
for
(
x
=
0
;
x
<
16
;
x
++
)
{
//red +0, green +1, blue +2, alpha +3
// thinking: GRBG
oPixels
[
4
*
(
offset
+
x
)
+
0
]
=
((
x
%
2
==
1
&&
y
%
2
==
0
)
)?
macroblock
[
y
][
x
]:
0
;
oPixels
[
4
*
(
offset
+
x
)
+
1
]
=
((
x
%
2
==
0
&&
y
%
2
==
0
)
||
(
x
%
2
==
1
&&
y
%
2
==
1
))?
macroblock
[
y
][
x
]:
0
;
oPixels
[
4
*
(
offset
+
x
)
+
2
]
=
((
x
%
2
==
0
&&
y
%
2
==
1
)
)?
macroblock
[
y
][
x
]:
0
;
oPixels
[
4
*
(
offset
+
x
)
+
3
]
=
255
;
}
}
}
for
(
y
=
0
;
y
<
16
;
y
++
)
{
offset
=
width
*
((
yb
<<
4
)
+
y
)
+
(
xb
<<
4
);
for
(
x
=
0
;
x
<
16
;
x
++
)
{
//red +0, green +1, blue +2, alpha +3
// thinking: GRBG
bi
=
2
*
(
y
%
2
)
+
x
%
2
;
oPixels
[
4
*
(
offset
+
x
)
+
0
]
=
((
bayerMosaic
[
bi
]
==
"R"
)
)?
macroblock
[
y
][
x
]:
0
;
oPixels
[
4
*
(
offset
+
x
)
+
1
]
=
((
bayerMosaic
[
bi
]
==
"Gr"
)
||
(
bayerMosaic
[
bi
]
==
"Gb"
))?
macroblock
[
y
][
x
]:
0
;
oPixels
[
4
*
(
offset
+
x
)
+
2
]
=
((
bayerMosaic
[
bi
]
==
"B"
)
)?
macroblock
[
y
][
x
]:
0
;
oPixels
[
4
*
(
offset
+
x
)
+
3
]
=
255
;
}
}
}
}
ctx
.
putImageData
(
outputImage
,
0
,
0
);
...
...
@@ -149,29 +157,79 @@ function demosaic_bilinear(ctx){
var
outputImage
=
ctx
.
getImageData
(
0
,
0
,
width
,
height
);
var
oPixels
=
outputImage
.
data
;
var
x_l
=
0
,
x_r
=
0
;
var
y_t
=
0
,
y_b
=
0
;
for
(
var
y
=
0
;
y
<
height
;
y
++
){
for
(
var
x
=
0
;
x
<
width
;
x
++
){
bi
=
2
*
(
y
%
2
)
+
x
%
2
;
x_l
=
(
x
==
0
)?
1
:(
x
-
1
);
x_r
=
(
x
==
(
width
-
1
))?(
width
-
2
):(
x
+
1
);
y_t
=
(
y
==
0
)?
1
:(
y
-
1
);
y_b
=
(
y
==
(
height
-
1
))?(
height
-
2
):(
y
+
1
);
//Gr
if
(
x
%
2
==
0
&&
y
%
2
==
0
){
oPixels
[
4
*
(
width
*
y
+
x
)
+
0
]
=
1
/
2
*
(
oPixels
[
4
*
(
width
*
(
y
+
0
)
+
(
x
-
1
))
+
0
]
+
oPixels
[
4
*
(
width
*
(
y
+
0
)
+
(
x
+
1
))
+
0
]);
oPixels
[
4
*
(
width
*
y
+
x
)
+
2
]
=
1
/
2
*
(
oPixels
[
4
*
(
width
*
(
y
-
1
)
+
(
x
+
0
))
+
2
]
+
oPixels
[
4
*
(
width
*
(
y
+
1
)
+
(
x
+
0
))
+
2
]);
if
(
bayerMosaic
[
bi
]
==
"Gr"
){
oPixels
[
4
*
(
width
*
y
+
x
)
+
0
]
=
1
/
2
*
(
oPixels
[
4
*
(
width
*
(
y
+
0
)
+
(
x
_l
))
+
0
]
+
oPixels
[
4
*
(
width
*
(
y
+
0
)
+
(
x_r
))
+
0
]);
oPixels
[
4
*
(
width
*
y
+
x
)
+
2
]
=
1
/
2
*
(
oPixels
[
4
*
(
width
*
(
y
_b
)
+
(
x
+
0
))
+
2
]
+
oPixels
[
4
*
(
width
*
(
y_t
)
+
(
x
+
0
))
+
2
]);
}
//R
if
(
x
%
2
==
1
&&
y
%
2
==
0
){
oPixels
[
4
*
(
width
*
y
+
x
)
+
1
]
=
1
/
4
*
(
oPixels
[
4
*
(
width
*
(
y
-
1
)
+
(
x
+
0
))
+
1
]
+
oPixels
[
4
*
(
width
*
(
y
+
0
)
+
(
x
-
1
))
+
1
]
+
oPixels
[
4
*
(
width
*
(
y
+
0
)
+
(
x
+
1
))
+
1
]
+
oPixels
[
4
*
(
width
*
(
y
+
1
)
+
(
x
+
0
))
+
1
]);
oPixels
[
4
*
(
width
*
y
+
x
)
+
2
]
=
1
/
4
*
(
oPixels
[
4
*
(
width
*
(
y
-
1
)
+
(
x
-
1
))
+
2
]
+
oPixels
[
4
*
(
width
*
(
y
-
1
)
+
(
x
+
1
))
+
2
]
+
oPixels
[
4
*
(
width
*
(
y
+
1
)
+
(
x
-
1
))
+
2
]
+
oPixels
[
4
*
(
width
*
(
y
+
1
)
+
(
x
+
1
))
+
2
]);
if
(
bayerMosaic
[
bi
]
==
"R"
){
oPixels
[
4
*
(
width
*
y
+
x
)
+
1
]
=
1
/
4
*
(
oPixels
[
4
*
(
width
*
(
y
_t
)
+
(
x
+
0
))
+
1
]
+
oPixels
[
4
*
(
width
*
(
y
+
0
)
+
(
x_l
))
+
1
]
+
oPixels
[
4
*
(
width
*
(
y
+
0
)
+
(
x_r
))
+
1
]
+
oPixels
[
4
*
(
width
*
(
y_b
)
+
(
x
+
0
))
+
1
]);
oPixels
[
4
*
(
width
*
y
+
x
)
+
2
]
=
1
/
4
*
(
oPixels
[
4
*
(
width
*
(
y
_t
)
+
(
x_l
))
+
2
]
+
oPixels
[
4
*
(
width
*
(
y_t
)
+
(
x_r
))
+
2
]
+
oPixels
[
4
*
(
width
*
(
y_b
)
+
(
x_l
))
+
2
]
+
oPixels
[
4
*
(
width
*
(
y_b
)
+
(
x_r
))
+
2
]);
}
//B
if
(
x
%
2
==
0
&&
y
%
2
==
1
){
oPixels
[
4
*
(
width
*
y
+
x
)
+
0
]
=
1
/
4
*
(
oPixels
[
4
*
(
width
*
(
y
-
1
)
+
(
x
-
1
))
+
0
]
+
oPixels
[
4
*
(
width
*
(
y
-
1
)
+
(
x
+
1
))
+
0
]
+
oPixels
[
4
*
(
width
*
(
y
+
1
)
+
(
x
-
1
))
+
0
]
+
oPixels
[
4
*
(
width
*
(
y
+
1
)
+
(
x
+
1
))
+
0
]);
oPixels
[
4
*
(
width
*
y
+
x
)
+
1
]
=
1
/
4
*
(
oPixels
[
4
*
(
width
*
(
y
-
1
)
+
(
x
+
0
))
+
1
]
+
oPixels
[
4
*
(
width
*
(
y
+
0
)
+
(
x
-
1
))
+
1
]
+
oPixels
[
4
*
(
width
*
(
y
+
0
)
+
(
x
+
1
))
+
1
]
+
oPixels
[
4
*
(
width
*
(
y
+
1
)
+
(
x
+
0
))
+
1
]);
if
(
bayerMosaic
[
bi
]
==
"B"
){
oPixels
[
4
*
(
width
*
y
+
x
)
+
0
]
=
1
/
4
*
(
oPixels
[
4
*
(
width
*
(
y
_t
)
+
(
x_l
))
+
0
]
+
oPixels
[
4
*
(
width
*
(
y_t
)
+
(
x_r
))
+
0
]
+
oPixels
[
4
*
(
width
*
(
y_b
)
+
(
x_l
))
+
0
]
+
oPixels
[
4
*
(
width
*
(
y_b
)
+
(
x_r
))
+
0
]);
oPixels
[
4
*
(
width
*
y
+
x
)
+
1
]
=
1
/
4
*
(
oPixels
[
4
*
(
width
*
(
y
_t
)
+
(
x
+
0
))
+
1
]
+
oPixels
[
4
*
(
width
*
(
y
+
0
)
+
(
x_l
))
+
1
]
+
oPixels
[
4
*
(
width
*
(
y
+
0
)
+
(
x_r
))
+
1
]
+
oPixels
[
4
*
(
width
*
(
y_b
)
+
(
x
+
0
))
+
1
]);
}
//Gb
if
(
x
%
2
==
1
&&
y
%
2
==
1
){
oPixels
[
4
*
(
width
*
y
+
x
)
+
0
]
=
1
/
2
*
(
oPixels
[
4
*
(
width
*
(
y
-
1
)
+
(
x
+
0
))
+
0
]
+
oPixels
[
4
*
(
width
*
(
y
+
1
)
+
(
x
+
0
))
+
0
]);
oPixels
[
4
*
(
width
*
y
+
x
)
+
2
]
=
1
/
2
*
(
oPixels
[
4
*
(
width
*
(
y
+
0
)
+
(
x
-
1
))
+
2
]
+
oPixels
[
4
*
(
width
*
(
y
+
0
)
+
(
x
+
1
))
+
2
]);
if
(
bayerMosaic
[
bi
]
==
"Gb"
){
oPixels
[
4
*
(
width
*
y
+
x
)
+
0
]
=
1
/
2
*
(
oPixels
[
4
*
(
width
*
(
y
_t
)
+
(
x
+
0
))
+
0
]
+
oPixels
[
4
*
(
width
*
(
y_b
)
+
(
x
+
0
))
+
0
]);
oPixels
[
4
*
(
width
*
y
+
x
)
+
2
]
=
1
/
2
*
(
oPixels
[
4
*
(
width
*
(
y
+
0
)
+
(
x
_l
))
+
2
]
+
oPixels
[
4
*
(
width
*
(
y
+
0
)
+
(
x_r
))
+
2
]);
}
}
}
ctx
.
putImageData
(
outputImage
,
0
,
0
);
}
\ No newline at end of file
}
function
saturation
(
ctx
){
var
width
=
ctx
.
canvas
.
width
;
var
height
=
ctx
.
canvas
.
height
;
var
inputImage
=
ctx
.
getImageData
(
0
,
0
,
width
,
height
);
var
iPixels
=
inputImage
.
data
;
var
r
,
g
,
b
;
var
Y
,
Cb
,
Cr
;
for
(
var
y
=
0
;
y
<
height
;
y
++
){
for
(
var
x
=
0
;
x
<
width
;
x
++
){
//don't forget to multiply?
r
=
iPixels
[
4
*
(
width
*
y
+
x
)
+
0
];
g
=
iPixels
[
4
*
(
width
*
y
+
x
)
+
1
];
b
=
iPixels
[
4
*
(
width
*
y
+
x
)
+
2
];
Y
=
0.299
*
r
+
0.5870
*
g
+
0.144
*
b
;
Cb
=
128
+
SATURATION
*
(
-
0.1687
*
r
-
0.3313
*
g
+
0.500
*
b
);
Cr
=
128
+
SATURATION
*
(
0.5
*
r
-
0.4187
*
g
-
0.0813
*
b
);
if
(
Cb
<
0
)
Cb
=
0
;
if
(
Cb
>
255
)
Cb
=
255
;
if
(
Cr
<
0
)
Cr
=
0
;
if
(
Cr
>
255
)
Cr
=
255
;
r
=
Y
+
1.402
*
(
Cr
-
128
);
g
=
Y
-
0.34414
*
(
Cb
-
128
)
-
0.71414
*
(
Cr
-
128
);
b
=
Y
+
1.772
*
(
Cb
-
128
);
if
(
r
<
0
)
r
=
0
;
if
(
r
>
255
)
r
=
255
;
if
(
g
<
0
)
g
=
0
;
if
(
g
>
255
)
g
=
255
;
if
(
b
<
0
)
b
=
0
;
if
(
b
>
255
)
b
=
255
;
iPixels
[
4
*
(
width
*
y
+
x
)
+
0
]
=
r
;
iPixels
[
4
*
(
width
*
y
+
x
)
+
1
]
=
g
;
iPixels
[
4
*
(
width
*
y
+
x
)
+
2
]
=
b
;
iPixels
[
4
*
(
width
*
y
+
x
)
+
3
]
=
255
;
}
}
ctx
.
putImageData
(
inputImage
,
0
,
0
);
}
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