I am new to blackberry.
I am trying to convert normal image into sketch effect.I have code to do that in ANDROID.
I have tried to implement it in Blackberry but unable to got output.Here is android code and my blackberry code.
This is android code-
public class ConvolutionMatrix
{
public static final int SIZE = 3;
public double[][] Matrix;
public double Factor = 1;
public double Offset = 1;
public ConvolutionMatrix(int size) {
Matrix = new double[size][size];
}
public void setAll(double value) {
for (int x = 0; x < SIZE; ++x) {
for (int y = 0; y < SIZE; ++y) {
Matrix[x][y] = value;
}
}
}
public void applyConfig(double[][] config) {
for(int x = 0; x < SIZE; ++x) {
for(int y = 0; y < SIZE; ++y) {
Matrix[x][y] = config[x][y];
}
}
}
public static Bitmap computeConvolution3x3(Bitmap src, ConvolutionMatrix matrix) {
int width = src.getWidth();
int height = src.getHeight();
Bitmap result = Bitmap.createBitmap(width, height, src.getConfig());
int A, R, G, B;
int sumR, sumG, sumB;
int[][] pixels = new int[SIZE][SIZE];
for(int y = 0; y < height - 2; ++y) {
for(int x = 0; x < width - 2; ++x) {
// get pixel matrix
for(int i = 0; i < SIZE; ++i) {
for(int j = 0; j < SIZE; ++j) {
pixels[i][j] = src.getPixel(x + i, y + j);
}
}
// get alpha of center pixel
A = Color.alpha(pixels[1][1]);
// init color sum
sumR = sumG = sumB = 0;
// get sum of RGB on matrix
for(int i = 0; i < SIZE; ++i) {
for(int j = 0; j < SIZE; ++j) {
sumR += (Color.red(pixels[i][j]) * matrix.Matrix[i][j]);
sumG += (Color.green(pixels[i][j]) * matrix.Matrix[i][j]);
sumB += (Color.blue(pixels[i][j]) * matrix.Matrix[i][j]);
}
}
// get final Red
R = (int)(sumR / matrix.Factor + matrix.Offset);
if(R < 0) { R = 0; }
else if(R > 255) { R = 255; }
// get final Green
G = (int)(sumG / matrix.Factor + matrix.Offset);
if(G < 0) { G = 0; }
else if(G > 255) { G = 255; }
// get final Blue
B = (int)(sumB / matrix.Factor + matrix.Offset);
if(B < 0) { B = 0; }
else if(B > 255) { B = 255; }
// apply new pixel
result.setPixel(x + 1, y + 1, Color.argb(A, R, G, B));
}
}
// final image
return result;
}
}
and following is my Blackberry code that I have tried-
public ConvolutionMatrix(int size) {
Matrix = new double[size][size];
}
public void setAll(double value) {
for (int x = 0; x < SIZE; ++x) {
for (int y = 0; y < SIZE; ++y) {
Matrix[x][y] = value;
}
}
}
public void applyConfig(double[][] config) {
for(int x = 0; x < SIZE; ++x) {
for(int y = 0; y < SIZE; ++y) {
Matrix[x][y] = config[x][y];
}
}
}
public static Bitmap computeConvolution3x3(Bitmap src, ConvolutionMatrix matrix) {
int width = src.getWidth();
int height = src.getHeight();
int A, R, G, B;
int sumR, sumG, sumB;
int[] argb= new int[width*height];
int[][]newargb=new int[width][height];
src.getARGB(argb, 0, width, 0, 0, width, height);
for(int y=0;y<=height;y++)
{
for (int x=0;x<=width;x++)
{
System.out.println(""+x);
System.out.println(""+y);
newargb[y][x]=argb[width*y+x];
}
}
int[][] pixels = new int[SIZE][SIZE];
for(int y = 0; y < height - 2; ++y) {
for(int x = 0; x < width - 2; ++x) {
// get pixel matrix
for(int i = 0; i < SIZE; ++i) {
for(int j = 0; j < SIZE; ++j) {
pixels[i][j] = newargb[x + i][ y + j];
}
}
A=pixels[1][1];
sumR = sumG = sumB = 0;
for(int i = 0; i < SIZE; ++i) {
for(int j = 0; j < SIZE; ++j) {
A =pixels[i][j] >> 24;
R =pixels[i][j]>> 16 & 0xFF;
G =pixels[i][j] >> 8 & 0xFF;
B =pixels[i][j] & 0xFF;
sumR += (R * matrix.Matrix[i][j]);
sumG += (G * matrix.Matrix[i][j]);
sumB += (B * matrix.Matrix[i][j]);
}
}
// get final Red
R = (int)(sumR / matrix.Factor + matrix.Offset);
if(R < 0) { R = 0; }
else if(R > 255) { R = 255; }
// get final Green
G = (int)(sumG / matrix.Factor + matrix.Offset);
if(G < 0) { G = 0; }
else if(G > 255) { G = 255; }
// get final Blue
B = (int)(sumB / matrix.Factor + matrix.Offset);
if(B < 0) { B = 0; }
else if(B > 255) { B = 255; }
for(int i = 0; i < SIZE; ++i) {
for(int j = 0; j < SIZE; ++j) {
pixels[i][j]=(A << 24) | (R << 16) | (G << 8) | B;
newargb[x ][ y]=pixels[i][j];
}
}
}
}
for(int y=0;y<=height;y++)
{
for (int x=0;x<=width;x++)
{
argb[width*y+x]=newargb[y][x];
}
}
src.setARGB(argb, 0, width, 0, 0, width, height);
return src;
}
}
Common Code for both android and Blackberry-
public Bitmap EmbossImage(Bitmap src) {
System.out.println("In Emboss Effect Image method");
double[][] SharpConfig = new double[][] {
{ 0 , -1, 0 },
{ -1, 5, -1 },
{ 0 , -1, 0 }
};
ConvolutionMatrix convMatrix = new ConvolutionMatrix(3);
convMatrix.setAll(0);
convMatrix.applyConfig(SharpConfig);
convMatrix.Factor = 1;
convMatrix.offset=130;
return ConvolutionMatrix.computeConvolution3x3(src, convMatrix);
}
I have found the answer for my own question.I found convolution related code from this site:
android image processing.
See in the comments part on this link page.
This is android code.Just make it compatible it for blackberry by changing Color class methods.
Related
I am doing Week 4 Filter-less for CS50, I get an error whne I try to compile my code
When I complie it is see this erorr.
/usr/bin/ld: /lib/x86_64-linux-gnu/Scrt1.o: in function _start': (.text+0x1b): undefined reference to main'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [: helpers] Error 1
This is my code
#include "helpers.h"
#include <math.h>
// Convert image to grayscale
void grayscale(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
float r = image[i][j].rgbtRed;
float g = image[i][j].rgbtGreen;
float b = image[i][j].rgbtBlue;
float grey = round((b + g + r)/3.0);
image[i][j].rgbtRed = image[i][j].rgbtGreen = image[i][j].rgbtBlue = grey;
}
}
return;
}
// Convert image to sepia
void sepia(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width / 2; j++)
{
int w = width - (j + 1);
RGBTRIPLE tmp = image[i][j];
image[i][j] = image[i][w];
image[i][w] = tmp;
}
}
return;
}
// Reflect image horizontally
void reflect(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int b = image[i][j].rgbtBlue;
int g = image[i][j].rgbtGreen;
int r = image[i][j].rgbtRed;
int sepiaRed = round((0.393 * r) + (0.769 * g) + (0.189 * b));
int sepiaGreen = round((0.349 * r) + (0.686 * g) + (0.168 * b));
int sepiaBlue = round((0.272 * r) + (0.534 * g) + (0.131 * b));
if (sepiaRed > 255)
{
sepiaRed = 255;
}
if (sepiaGreen > 255)
{
sepiaGreen = 255;
}
if (sepiaBlue > 255)
{
sepiaBlue = 255;
}
image[i][j].rgbtBlue = sepiaBlue;
image[i][j].rgbtGreen = sepiaGreen;
image[i][j].rgbtRed = sepiaRed;
}
}
return;
}
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
RGBTRIPLE tmp[height][width];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
tmp[i][j] = image[i][j];
}
}
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int totalRed = 0;
int totalGreen = 0;
int totalBlue = 0;
float counter = 0.00;
for (int x = -1; x < 2; x++)
{
for (int y = -1; y < 2; y++)
{
int X = i + x;
int Y = j + y;
if (X < 0 || Y < 0 || X > (height - 1) || Y > (width - 1))
{
continue;
}
totalRed += image[X][Y].rgbtRed;
totalGreen += image[X][Y].rgbtGreen;
totalBlue += image[X][Y].rgbtBlue;
counter++;
}
tmp[i][j].rgbtRed = round(totalRed / counter);
tmp[i][j].rgbtGreen = round(totalGreen / counter);
tmp[i][j].rgbtBlue = round(totalBlue / counter);
}
}
}
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
image[i][j].rgbtRed = tmp[i][j].rgbtRed;
image[i][j].rgbtGreen = tmp[i][j].rgbtGreen;
image[i][j].rgbtBlue = tmp[i][j].rgbtBlue;
}
}
return;
}
first I gave the following error in the code
int KK = 10;
int colors[KK];
then I wrote const int instead of kk and fixed the error
I'm using the opencv library but I'm getting an error somewhere. When i and j are 713 48, they do not give an error, but in the next cycle, i and j are 713 and 49, and they give an error code.(OpenCV Error: Assertion failed (dims <= 2 && data && (unsigned)i0 < (unsigned)size.p[0] && (unsigned)(i1*DataType<_Tp>::channels) < (unsigned)(size.p[1]*channels()) && ((((sizeof(size_t)<<28)|0x8442211) >> ((DataType<_Tp>::depth) & ((1 << 3) - 1))*4) & 15) == elemSize1()) in cv::Mat::at, file c:\opencv\build\include\opencv2\core\mat.hpp, line 548)
the error gives in this row.
clustered.at(i,j) = (float)(colors[bestLabels.at(1,z)]);
I share the detailed code below
int KK = 10;
int colors[KK];
Mat p;
Mat bestLabels, centers;
vector<Mat> bgr, bgrBN;
split(frame_color, bgr);
Mat mask, clustered;
Mat clusteredAll = Mat::zeros(frame_color.rows, frame_color.cols, CV_32F);
for (int k = 0; k < contoursN.size(); k++)
{
mask = Mat::zeros(frame_color.rows, frame_color.cols, CV_8U);
drawContours(mask, contoursN, k, CV_RGB(255,255,255), CV_FILLED);
clustered = Mat::zeros(frame_color.rows, frame_color.cols, CV_32F);
int A = 0;
for (int i = 0; i < frame_color.rows; i++)
for (int j = 0; j < frame_color.cols; j++)
if (mask.at<uchar>(i,j) != 0)
A++;
if (A > 20)
{
p = Mat::zeros(A, G, CV_32F);
double moy = 0;
int z = 0;
for (int i = 0; i < frame_color.rows; i++)
{
for (int j = 0; j < frame_color.cols; j++)
{
if (mask.at<uchar>(i,j) != 0)
{
p.at<float>(z,0) = bgr[0].data[i*frame_color.cols+j] / 255.0;
p.at<float>(z,1) = bgr[1].data[i*frame_color.cols+j] / 255.0;
p.at<float>(z,2) = bgr[2].data[i*frame_color.cols+j] / 255.0;
z++;
moy = moy + frame.at<uchar>(i,j);
}
}
}
moy = moy/z;
double var = 0;
for (int i = 0; i < frame_color.rows; i++)
for (int j = 0; j < frame_color.cols; j++)
if (mask.at<uchar>(i,j) != 0)
var = var+(frame.at<uchar>(i,j) - moy)*(frame.at<uchar>(i,j) - moy);
var = var/(z*z);
int K = 1 + log(1+(A/A0)+(var/var0));
kmeans(p, K, bestLabels, TermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 10, 1.0), 3, KMEANS_PP_CENTERS, centers);
for(int i=0; i<KK; i++)
colors[i] = 255/(i+1);
z = 0;
for (int i = 0; i < frame_color.rows; i++)
{
for (int j = 0; j < frame_color.cols; j++)
{
if (mask.at<uchar>(i,j) != 0)
{
clustered.at<float>(i,j) = (float)(colors[bestLabels.at<int>(1,z)]);
z++;
}
}
}
clusteredAll = clusteredAll + clustered;
clustered.convertTo(clustered, CV_8U);
}
I'm trying to write the simplest possible image comparison function.
The idea is to have a target image and a collection of n number of different images.
The goal is to pick the image which is most similar to the target image.
So far my method consists of defining the euclidean HSB distance from pixel to pixel in a resized image and have been trying to do a PImage function that returns the winner image. I already wrote a float function that ranks the image list from winner to loser but I would like to skip this step to make the process way more concise.
The issue is at the PImage difference(PImage){
function, the program outputs an error on the line:
float x1 = brightness(imageKey.pixels[i]);
The error is ArrayIndexOutOfBoundsException
Here's the entire code:
//CLICK ON S TO SAVE FRAMES TO FOLDER
int series = 50; //
PImage[] collection = new PImage[series];
PImage imageKey,imageKey2, imageKeyHUE, imageKeySUM, imageKeySAT; //target image alias with ready operations
int imageWidth = 800;
int leftAlign = 850 ;
void setup()
{
size(1200,600);
background(255);
frameRate(random(1,10.0));
for ( int i = 0; i< collection.length; i++ )
{
collection[i] = loadImage( "Image_"+ i + ".jpg" );
}
//_____________________________________________TARGET IMAGE AND NAME TEXT
textSize(10);
fill(0);
text("target image", leftAlign, 220);
textSize(15);
text("central london", leftAlign, 240);
text("comparison methods", leftAlign, 290);
//_____________________________________________________________________BUTTONS
imageKey = loadImage("Image_0.jpg");
imageKey.resize(240, 180);
image(imageKey, leftAlign,25);
imageKeySAT= loadImage("Image_0.jpg");
imageKeySAT.resize(60,60);
imageKeySAT = saturation(imageKeySAT);
image(imageKeySAT, leftAlign+140,300);
imageKeySUM = loadImage("Image_0.jpg");
imageKeySUM.resize(60,60);
imageKeySUM = sum(imageKeySUM);
image(imageKeySUM, leftAlign+70,300);
imageKeyHUE = loadImage("Image_0.jpg");
imageKeyHUE.resize(60,60);
imageKeyHUE = hue(imageKeyHUE);
image(imageKeyHUE, leftAlign,300);
textSize(20);
text("CLICK HERE TO", leftAlign, 430);
text("STOP AT WINNER", leftAlign, 450);
}
void draw()
{
//______________________________________________SHOW IMAGES ARRAY
image(collection[int(random(0,series))],0,0);
//______________________________________________HISTOGRAMS
histogramhue();
histogramsat();
histogrambright();
//______________________________________________SUM METHOD
//float Vector_Approach(PImage sumSatin){
//}
}
void keyPressed()
{
if(key=='s') saveFrame("images/image-######.jpg");
}
PImage difference(PImage satin)
{
colorMode(HSB);
satin.loadPixels();
imageKey.loadPixels();
PImage satout = createImage(satin.width, satin.height, RGB);
satout.loadPixels();
for(int i = imageWidth; i<satout.pixels.length-imageWidth; i++)
{
float x1 = brightness(imageKey.pixels[i]);
float b0 = brightness(satin.pixels[i]);
// float y1 = brightness(satin.pixels[i+1]);
float value = x1-b0;
satout.pixels[i] = color(0,0,value);
}
satout.updatePixels();
return satout;
}
void mouseReleased(){
//______________________________________________BUTTON OVER
for ( int i = 0; i< collection.length; i++ )
if (mouseX > leftAlign && mouseX < (leftAlign + 60) && mouseY > 300 && mouseY < 360){
collection[i] = loadImage( "Image_"+ i + ".jpg" );
collection[i] = hue(collection[i]); histogramhue();
noStroke(); fill(255); rect(leftAlign,360,200,40); fill(0);
textSize(10);text("comparison by hue", leftAlign, 380);
} else if (mouseX > (leftAlign + 70) && mouseX < (leftAlign + 130) && mouseY > 300 && mouseY < 360)
{
collection[i] = loadImage( "Image_"+ i + ".jpg" );
collection[i] = sum(collection[i]);
noStroke(); fill(255); rect(leftAlign,360,200,40); fill(0);
textSize(10);text("comparison by sum", leftAlign, 380);
}else if (mouseX > (leftAlign + 140) && mouseX < (leftAlign + 200) && mouseY > 300 && mouseY < 360)
{
collection[i] = loadImage( "Image_"+ i + ".jpg" );
collection[i] = saturation(collection[i]);
noStroke(); fill(255); rect(leftAlign,360,200,40); fill(0);
textSize(10);text("comparison by saturation", leftAlign, 380);
}else if (mouseX > leftAlign && mouseX < 1200 && mouseY > 340 && mouseY < 600)
{
collection[i] = loadImage( "Image_"+ i + ".jpg" );
collection[i] = difference(collection[i]);
noStroke(); fill(255); rect(leftAlign,360,200,40); fill(0);
textSize(10);text("WINNER IMAGE!!!!", leftAlign, 380);
}else{
collection[i] = loadImage( "Image_"+ i + ".jpg" );
noStroke(); fill(255); rect(leftAlign,360,200,40); fill(0);
}
}
/* HSB PImage Methods */
//HUE -------> /** CHOSEN METHOD**/
//SATURATION -------> /** CHOSEN METHOD**/
//SUM -------> /** CHOSEN METHOD**/
PImage hue(PImage satin)
{
colorMode(HSB);
satin.loadPixels();
PImage satout = createImage(satin.width, satin.height, HSB);
satout.loadPixels();
for (int j = 0; j < satout.pixels.length; j++)
{
satout.pixels[j] = color(hue(satin.pixels[j]),255,255);
}
satout.updatePixels();
return satout;
}
PImage saturation(PImage satin)
{
colorMode(HSB);
satin.loadPixels();
PImage satout = createImage(satin.width, satin.height, RGB);
satout.loadPixels();
for (int j = 0; j < satout.pixels.length; j++)
{
satout.pixels[j] = color(saturation(satin.pixels[j]));
}
satout.updatePixels();
//colorMode(RGB);
return satout;
}
PImage sum(PImage satin)
{
colorMode(HSB);
satin.loadPixels();
PImage satout = createImage(satin.width, satin.height, RGB);
satout.loadPixels();
for(int i = imageWidth; i<satout.pixels.length-imageWidth; i++)
{
float b0 = brightness(satin.pixels[i]);
float x1 = brightness(satin.pixels[i-1]);
float y1 = brightness(satin.pixels[i-imageWidth]);
float xdiff = b0-x1;
float ydiff = b0-y1;
float value = (510 + xdiff + ydiff)/3;
satout.pixels[i] = color(0,0,value);
}
satout.updatePixels();
return satout;
}
//REFERENCE HISTOGRAM TAKEN FROM A PROGRAMMING HANDBOOK FOR VISUAL DESIGNERS AND ARTISTS BY BEN FRY ET AL
void histogramhue(){
PImage img = loadImage("Image_0.jpg");
int[] hist = new int[600];
// Calculate the histogram
for (int i = 0; i < img.width; i++) {
for (int j = 0; j < img.height; j++) {
int hue = int(hue(get(i, j)));
hist[hue]++;
}
}
int histMax = max(hist);
stroke(255,250); strokeWeight(5);
// Draw half of the histogram (skip every second value)
for (int i = 0; i < img.width; i += 20) {
int which = int(map(i, 0, img.width, 0, 255));
int y = int(map(hist[which], 0, histMax, img.height, 0));
line(i, img.height, i, y);
}}
void histogramsat(){
PImage img = loadImage("Image_0.jpg");
int[] hist = new int[600];
for (int i = 0; i < img.width; i++) {
for (int j = 0; j < img.height; j++) {
int sat = int(saturation(get(i, j)));
hist[sat]++;
}
}
int histMax = max(hist);
stroke(255,150);strokeWeight(10);
for (int i = 0; i < img.width; i += 20) {
int which = int(map(i, 0, img.width, 0, 255));
int y = int(map(hist[which], 0, histMax, img.height, 0));
line(i, img.height, i, y);
}}
void histogrambright(){
PImage img = loadImage("Image_0.jpg");
int[] hist = new int[600];
for (int i = 0; i < img.width; i++) {
for (int j = 0; j < img.height; j++) {
int bright = int(brightness(get(i, j)));
hist[bright]++;
}
}
int histMax = max(hist);
stroke(255, 150);strokeWeight(20);
for (int i = 0; i < img.width; i += 20) {
int which = int(map(i, 0, img.width, 0, 255));
int y = int(map(hist[which], 0, histMax, img.height, 0));
line(i, img.height, i, y);
}}
In isolation your function does seem to work:
PImage imageKey,testImage;
int imageWidth = 800;
int imageHeight = 600;
void setup(){
size(1600,600);
//fake imageKey
imageKey = getNoise(imageWidth,imageHeight);
//fake test image
testImage = getNoise(imageWidth,imageHeight);
image(testImage,0,0);
image(difference(testImage),800,0);
}
PImage getNoise(int width,int height){
PImage out = createImage(width,height,RGB);
for(int i = 0 ; i < out.pixels.length; i++)
out.pixels[i] = color(random(255),random(255),random(255));
out.updatePixels();
return out;
}
PImage difference(PImage satin)
{
colorMode(HSB);
satin.loadPixels();
imageKey.loadPixels();
PImage satout = createImage(satin.width, satin.height, RGB);
satout.loadPixels();
for (int i = imageWidth; i<satout.pixels.length-imageWidth; i++)
{
float x1 = brightness(imageKey.pixels[i]);
float b0 = brightness(satin.pixels[i]);
// float y1 = brightness(satin.pixels[i+1]);
float value = x1-b0;
//println(i,x1,b0,x1-b0,value);
satout.pixels[i] = color(0, 0, value);
}
satout.updatePixels();
return satout;
}
I can't test your actual setup as I don't have access to your images, but the ArrayIndexOutOfBoundsException is probably because your i counter goes beyond the number of pixels in imageKey. You can test this by putting checking if i < imageKey.pixels.length. My guess is the images aren't the same dimensions and therefore don't have the same number of pixels.
Other notes that are going slightly off-topic:
Your difference() function is tightly coupled to the imageKey and imageWidth variables. You might want to make your functions loosely coupled so they can be reused easily in other contexts. You could start by making these two variables extra parameters/arguments of the function
You might also want to look at euclidean distance between colours (in a perceptual colour space such as Lab*). Have a look at this answer.Even though it's an OpenFrameworks answer, it should be easy to adapt to Processing's color and PVector types.
I want to swap the U and V bit in YUV format, from NV12
YYYYYYYY UVUV // each letter presents a bit
to NV21
YYYYYYYY VUVU
I leave the Y planar alone, and handle the U and V planar by the function below
uchar swap(uchar in) {
uchar out = ((in >> 1) & 0x55) | ((in << 1) & 0xaa);
return out;
}
But I cannot get the desired result, the colour of the output image still not correct.
How can I swap U and V planar correctly?
Found the problem. UV should be manipulated in byte format, not bit.
byte[] yuv = // ...
final int length = yuv.length;
for (int i1 = 0; i1 < length; i1 += 2) {
if (i1 >= width * height) {
byte tmp = yuv[i1];
yuv[i1] = yuv[i1+1];
yuv[i1+1] = tmp;
}
}
try this method (-_-)
IFrameCallback iFrameCallback = new IFrameCallback() {
#Override
public void onFrame(ByteBuffer frame) {
//get nv12 data
byte[] b = new byte[frame.remaining()];
frame.get(b);
//nv12 data to nv21
NV12ToNV21(b, 1280, 720);
//send NV21 data
BVPU.InputVideoData(nv21, nv21.length,
System.currentTimeMillis() * 1000, 1280, 720);
}
};
byte[] nv21;
private void NV12ToNV21(byte[] data, int width, int height) {
nv21 = new byte[data.length];
int framesize = width * height;
int i = 0, j = 0;
System.arraycopy(data, 0, nv21, 0, framesize);
for (i = 0; i < framesize; i++) {
nv21[i] = data[i];
}
for (j = 0; j < framesize / 2; j += 2) {
nv21[framesize + j - 1] = data[j + framesize];
}
for (j = 0; j < framesize / 2; j += 2) {
nv21[framesize + j] = data[j + framesize - 1];
}
}
There is a perspective image issue when I read a picture that is taken from the camera. When the direction is north, the picture looks like needed to be rotated 270 degrees. When the direction is east, picture should be rotated 180 degrees. But it's good when the direction is west. I tried getMetaData().getKeyValue("orientation") in EncodedImage for producing a good rotating formula, but it returned empty string. Please help me how to solve this problem.
Found solution here:
https://gist.github.com/3788313
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.microedition.io.Connector;
import javax.microedition.io.file.FileConnection;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.EncodedImage;
public class ExifRotate {
/**
* Flip the image horizontally.
*/
public static final int FLIP_H = 1;
/**
* Flip the image vertically.
*/
public static final int FLIP_V = 2;
/**
* Flip the image horizontally and vertically.
*/
public static final int FLIP_HV = 3;
/**
* Rotate the image 90 degrees clockwise.
*/
public static final int FLIP_90CW = 4;
/**
* Rotate the image 90 degrees counter-clockwise.
*/
public static final int FLIP_90CCW = 5;
/**
* Rotate the image 180 degrees.
*/
public static final int FLIP_180 = 6;
private final static int read2bytes(InputStream in) throws IOException {
return in.read() << 8 | in.read();
}
private final static int readByte(InputStream in) throws IOException {
return in.read();
}
public static Bitmap readImageFromFile(String filename, int width, int height) throws IOException {
EncodedImage img = null;
byte[] data = null;
FileConnection file = null;
try {
file = (FileConnection) Connector.open(filename, Connector.READ);
int fileSize = (int) file.fileSize();
if (fileSize == 0) {
throw new IOException("File is empty");
}
data = new byte[fileSize];
InputStream input = file.openInputStream();
input.read(data);
input.close();
img = EncodedImage.createEncodedImage(data, 0, data.length);
int orientation = -1;
if ( filename.toLowerCase().endsWith(".jpg") || filename.toLowerCase().endsWith(".jpeg")) {
ByteArrayInputStream is = new ByteArrayInputStream( data );
orientation = getRotation(is);
}
if ( orientation == 2 ) {
return rotateBitmap(img.getBitmap(), ImageUtil.FLIP_H);
} else if ( orientation == 3 ) {
return rotateBitmap(img.getBitmap(), ImageUtil.FLIP_180);
} else if ( orientation == 4 ) {
return rotateBitmap(img.getBitmap(), ImageUtil.FLIP_V);
} else if ( orientation == 5 ) {
Bitmap tmp = rotateBitmap(img.getBitmap(), ImageUtil.FLIP_H);
tmp = rotateBitmap(tmp, ImageUtil.FLIP_90CCW);
return tmp;
} else if ( orientation == 6 ) {
return rotateBitmap(img.getBitmap(), ImageUtil.FLIP_90CW);
} else if ( orientation == 7 ) {
Bitmap tmp = rotateBitmap(img.getBitmap(), ImageUtil.FLIP_H);
tmp = rotateBitmap(tmp, ImageUtil.FLIP_90CW);
return tmp;
} else if ( orientation == 8 ) {
return rotateBitmap(img.getBitmap(), ImageUtil.FLIP_90CCW);
} else {
return img.getBitmap();
}
} finally {
if (file != null) {
try { file.close(); }
catch(Exception ex){}
}
}
}
public static int getRotation(InputStream in) throws IOException {
int [] exif_data = new int[100];
int n_flag = 0, set_flag = 0;
int is_motorola = 0;
/* Read File head, check for JPEG SOI + Exif APP1 */
for (int i = 0; i < 4; i++)
exif_data[i] = readByte(in);
if (exif_data[0] != 0xFF || exif_data[1] != 0xD8 || exif_data[2] != 0xFF || exif_data[3] != 0xE1)
return -2;
/* Get the marker parameter length count */
int length = read2bytes(in);
// exif_data = new int[length];
/* Length includes itself, so must be at least 2 */
/* Following Exif data length must be at least 6 */
if (length < 8)
return -1;
length -= 8;
/* Read Exif head, check for "Exif" */
for (int i = 0; i < 6; i++)
exif_data[i] = in.read();
if (exif_data[0] != 0x45 || exif_data[1] != 0x78 || exif_data[2] != 0x69 || exif_data[3] != 0x66 || exif_data[4] != 0 || exif_data[5] != 0)
return -1;
/* Read Exif body */
length = length > exif_data.length ? exif_data.length : length;
for (int i = 0; i < length; i++)
exif_data[i] = in.read();
if (length < 12)
return -1; /* Length of an IFD entry */
/* Discover byte order */
if (exif_data[0] == 0x49 && exif_data[1] == 0x49)
is_motorola = 0;
else if (exif_data[0] == 0x4D && exif_data[1] == 0x4D)
is_motorola = 1;
else
return -1;
/* Check Tag Mark */
if (is_motorola == 1) {
if (exif_data[2] != 0)
return -1;
if (exif_data[3] != 0x2A)
return -1;
} else {
if (exif_data[3] != 0)
return -1;
if (exif_data[2] != 0x2A)
return -1;
}
/* Get first IFD offset (offset to IFD0) */
int offset;
if (is_motorola == 1) {
if (exif_data[4] != 0)
return -1;
if (exif_data[5] != 0)
return -1;
offset = exif_data[6];
offset <<= 8;
offset += exif_data[7];
} else {
if (exif_data[7] != 0)
return -1;
if (exif_data[6] != 0)
return -1;
offset = exif_data[5];
offset <<= 8;
offset += exif_data[4];
}
if (offset > length - 2)
return -1; /* check end of data segment */
/* Get the number of directory entries contained in this IFD */
int number_of_tags;
if (is_motorola == 1) {
number_of_tags = exif_data[offset];
number_of_tags <<= 8;
number_of_tags += exif_data[offset + 1];
} else {
number_of_tags = exif_data[offset + 1];
number_of_tags <<= 8;
number_of_tags += exif_data[offset];
}
if (number_of_tags == 0)
return -1;
offset += 2;
/* Search for Orientation Tag in IFD0 */
for (;;) {
if (offset > length - 12)
return -1; /* check end of data segment */
/* Get Tag number */
int tagnum;
if (is_motorola == 1) {
tagnum = exif_data[offset];
tagnum <<= 8;
tagnum += exif_data[offset + 1];
} else {
tagnum = exif_data[offset + 1];
tagnum <<= 8;
tagnum += exif_data[offset];
}
if (tagnum == 0x0112)
break; /* found Orientation Tag */
if (--number_of_tags == 0)
return -1;
offset += 12;
}
/*
* if (set_flag==1) { Set the Orientation value if (is_motorola==1) {
* exif_data[offset+2] = 0; Format = unsigned short (2 octets)
* exif_data[offset+3] = 3; exif_data[offset+4] = 0; Number Of
* Components = 1 exif_data[offset+5] = 0; exif_data[offset+6] = 0;
* exif_data[offset+7] = 1; exif_data[offset+8] = 0; exif_data[offset+9]
* = set_flag; exif_data[offset+10] = 0; exif_data[offset+11] = 0; }
* else { exif_data[offset+2] = 3; Format = unsigned short (2 octets)
* exif_data[offset+3] = 0; exif_data[offset+4] = 1; Number Of
* Components = 1 exif_data[offset+5] = 0; exif_data[offset+6] = 0;
* exif_data[offset+7] = 0; exif_data[offset+8] = set_flag;
* exif_data[offset+9] = 0; exif_data[offset+10] = 0;
* exif_data[offset+11] = 0; } }
*/
// else {
/* Get the Orientation value */
if (is_motorola == 1) {
if (exif_data[offset + 8] != 0)
return -1;
set_flag = exif_data[offset + 9];
} else {
if (exif_data[offset + 9] != 0)
return -1;
set_flag = exif_data[offset + 8];
}
if (set_flag > 8)
return -1;
// }
/* Write out Orientation value */
if (n_flag == 1)
System.out.println("set_flag " + set_flag);
else
System.out.println("set_flag " + set_flag);
return set_flag;
}
public static Bitmap rotateBitmap(Bitmap src, int operation) {
int width = src.getWidth();
int height = src.getHeight();
int[] inPixels = new int[width*height];
src.getARGB(inPixels, 0, width, 0, 0, width, height);
int x = 0, y = 0;
int w = width;
int h = height;
int newX = 0;
int newY = 0;
int newW = w;
int newH = h;
switch (operation) {
case FLIP_H:
newX = width - (x + w);
break;
case FLIP_V:
newY = height - (y + h);
break;
case FLIP_HV:
newW = h;
newH = w;
newX = y;
newY = x;
break;
case FLIP_90CW:
newW = h;
newH = w;
newX = height - (y + h);
newY = x;
break;
case FLIP_90CCW:
newW = h;
newH = w;
newX = y;
newY = width - (x + w);
break;
case FLIP_180:
newX = width - (x + w);
newY = height - (y + h);
break;
}
int[] newPixels = new int[newW * newH];
int index, newRow, newCol, newIndex;
if ( operation == FLIP_H ) {
for (int row = 0; row < h; row++) {
for (int col = 0; col < w; col++) {
index = row * width + col;
newRow = row;
newCol = w - col - 1;
newIndex = newRow * newW + newCol;
newPixels[newIndex] = inPixels[index];
}
}
} else if ( operation == FLIP_V ) {
for (int row = 0; row < h; row++) {
for (int col = 0; col < w; col++) {
index = row * width + col;
newRow = h - row - 1;
newCol = col;
newIndex = newRow * newW + newCol;
newPixels[newIndex] = inPixels[index];
}
}
} else if ( operation == FLIP_HV ) {
for (int row = 0; row < h; row++) {
for (int col = 0; col < w; col++) {
index = row * width + col;
newRow = col;
newCol = row;
newIndex = newRow * newW + newCol;
newPixels[newIndex] = inPixels[index];
}
}
} else if ( operation == FLIP_90CW ) {
for (int row = 0; row < h; row++) {
for (int col = 0; col < w; col++) {
index = row * width + col;
newRow = col;
newCol = h - row - 1;
newIndex = newRow * newW + newCol;
newPixels[newIndex] = inPixels[index];
}
}
} else if ( operation == FLIP_90CCW ) {
for (int row = 0; row < h; row++) {
for (int col = 0; col < w; col++) {
index = row * width + col;
newRow = w - col - 1;
newCol = row;
newIndex = newRow * newW + newCol;
newPixels[newIndex] = inPixels[index];
}
}
} else if ( operation == FLIP_180 ) {
for (int row = 0; row < h; row++) {
for (int col = 0; col < w; col++) {
index = row * width + col;
newRow = h - row - 1;
newCol = w - col - 1;
newIndex = newRow * newW + newCol;
newPixels[newIndex] = inPixels[index];
}
}
}
Bitmap dst = new Bitmap( newW, newH );
dst.setARGB(newPixels, 0, newW, 0, 0, newW, newH);
return dst;
}
}