Nice work everyone!
Class Notes – Resize Camera Image – Out of Memory Issue
String imageFilePath = "myfavpict.jpg";
PImage cameraImage;
void setup() {
orientation(LANDSCAPE);
// Create a File object out of that
File imageFile = new File(android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + imageFilePath);
// Create a Uri out of that
android.net.Uri imageFileUri = android.net.Uri.fromFile(imageFile);
// Create the Intent that triggers the camera
android.content.Intent i = new android.content.Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
// Tell the camera application where we want the resulting image saved
i.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, imageFileUri);
// Start the Camera
startActivityForResult(i, 0);
}
void draw() {
if (cameraImage != null) {
//image(cameraImage, 0, 0, width, height);
cameraImage.loadPixels();
loadPixels();
for (int x = 0; x < cameraImage.width && x < width; x++) {
for (int y = 0; y < cameraImage.height && y < height; y++) {
int r = int(red(cameraImage.pixels[x+cameraImage.width*y]));
color c = color(r,r,r);
pixels[x+cameraImage.width*y] = c;
}
}
updatePixels();
filter(INVERT);
}
}
protected void onActivityResult(int requestCode, int resultCode, android.content.Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if (resultCode == RESULT_OK) {
// We know the location via the imageFilePath String so load it into a standard Processing PImage
println(imageFilePath);
resizeImage(android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + imageFilePath, android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + "/smallimage.jpg");
cameraImage = loadImage(android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + "smallimage.jpg");
println("Should have loaded Image");
}
}
// Loads an image from disk at screen resolution and saves it back out at the same size.
void resizeImage(String imageFilePath, String newImageFilePath) {
try {
// Load up the image's dimensions not the image itself
android.graphics.BitmapFactory.Options bmpFactoryOptions = new android.graphics.BitmapFactory.Options();
bmpFactoryOptions.inJustDecodeBounds = true;
android.graphics.Bitmap bmp = android.graphics.BitmapFactory.decodeFile(imageFilePath, bmpFactoryOptions);
int heightRatio = (int) Math.ceil(bmpFactoryOptions.outHeight / (float) height);
int widthRatio = (int) Math.ceil(bmpFactoryOptions.outWidth / (float) width);
println("HEIGHTRATIO: " + heightRatio);
println("WIDTHRATIO: " + widthRatio);
// If both of the ratios are greater than 1, one of the sides of // the image is greater than the screen
if (heightRatio > 1 && widthRatio > 1) {
if (heightRatio > widthRatio) {
// Height ratio is larger, scale according to it
bmpFactoryOptions.inSampleSize = heightRatio;
}
else {
// Width ratio is larger, scale according to it
bmpFactoryOptions.inSampleSize = widthRatio;
}
}
// Decode it for real
bmpFactoryOptions.inJustDecodeBounds = false;
bmp = android.graphics.BitmapFactory.decodeFile(imageFilePath, bmpFactoryOptions);
java.io.File newImageFile = new java.io.File(newImageFilePath);
android.net.Uri newImageUri = android.net.Uri.fromFile(newImageFile);
OutputStream imageFileOS = getContentResolver().openOutputStream(newImageUri);
bmp.compress(android.graphics.Bitmap.CompressFormat.JPEG, 90, imageFileOS);
println("Resized image, wrote out to: " + newImageFile.getAbsolutePath());
}
catch (Exception e) {
println(e.toString());
e.printStackTrace();
}
}
Scaffolding
final int LOADING = 0;
final int HOME = 1;
final int PLAY = 2;
int screenNumber = LOADING;
void setup() {
}
void draw() {
if (screenNumber == LOADING) {
drawLoading();
} else if (screenNumber == HOME) {
drawHome();
} else if (screenNumber == PLAY) {
drawPlay();
}
}
void drawLoading() {
line(0,0,width,height);
}
void drawHome() {
}
void drawPlay() {
drawAnimation();
drawLyrics();
// Draw buttons
}
void drawAnimation() {
}
void drawLyrics() {
}
void mousePressed() {
if (screenNumber == LOADING) {
mousePressedLoading();
} else if (screenNumber == HOME) {
mousePressedHome();
} else if (screenNumber == PLAY) {
mousePressedPlay();
}
}
void mousePressedLoading() {
screenNumber = HOME;
}
void mousePressedHome() {
}
void mousePressedPlay() {
// Test Buttons
// Start Play/STop Play
startMusic();
stopMusic();
startRecording();
stopRecording();
}
Player Screen
int lyricNumber = 0;
String[] lyrics = {
“Every night in my dreams”,
“I see you, I feel you”,
“”
};
SoundPlayer titanic;
void setup() {
titanic = new SoundPlayer(this,”Titanic.mid”);
titanic.play();
}
void draw() {
background(0);
textMode(SCREEN);
text(lyrics[lyricNumber],width/2,height/2);
}
void mousePressed() {
println(titanic.getPosition());
lyricNumber++;
if (lyricNumber >= lyrics.length) {
lyricNumber = 0;
}
}
And here is the song: http://rainbowsendpress.com/midi/Titanic.mid
Camera Image Rotation
On most Android devices, the image taken by the camera is while the camera is in landscape mode. Unfortunately, we don’t know by simply loading the image what the orientation is when the image was taken. The easiest way to rectify the situation is to lock our application in landscape mode:
void setup() {
orientation(LANDSCAPE);
...
}
The opposite is portrait mode:
orientation(PORTRAIT);
Speech Recognition
Just a quick example:
final int VOICE_RECOGNITION_REQUEST_CODE = 1234;
void setup() {
}
void draw() {
}
void mousePressed() {
android.content.Intent intent = new android.content.Intent(android.speech.RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
// Specify the calling package to identify your application
intent.putExtra(android.speech.RecognizerIntent.EXTRA_CALLING_PACKAGE, getClass().getPackage().getName());
// Display an hint to the user about what he should say.
intent.putExtra(android.speech.RecognizerIntent.EXTRA_PROMPT, "Speech recognition demo");
// Given an hint to the recognizer about what the user is going to say
intent.putExtra(android.speech.RecognizerIntent.EXTRA_LANGUAGE_MODEL,
android.speech.RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
// Specify how many results you want to receive. The results will be sorted
// where the first result is the one with higher confidence.
intent.putExtra(android.speech.RecognizerIntent.EXTRA_MAX_RESULTS, 5);
startActivityForResult(intent, VOICE_RECOGNITION_REQUEST_CODE);
}
/**
* Handle the results from the recognition activity.
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, android.content.Intent data) {
if (requestCode == VOICE_RECOGNITION_REQUEST_CODE && resultCode == RESULT_OK) {
// The list of possible matches
ArrayList matches = data.getStringArrayListExtra(android.speech.RecognizerIntent.EXTRA_RESULTS);
if (matches.size() > 0) {
println((String)(matches.get(0)));
}
}
}
OutOfMemory
In some instances, the image returned by the camera may be too big for our application to load into memory outright. In order to rectify this situation, here is a method that you can use to resize an image on disk. Just pass in the path of the original and where you want to new image saved.
// Loads an image from disk at screen resolution and saves it back out at the same size.
void resizeImage(String imageFilePath, String newImageFilePath) {
try {
// Load up the image's dimensions not the image itself
android.graphics.BitmapFactory.Options bmpFactoryOptions = new android.graphics.BitmapFactory.Options();
bmpFactoryOptions.inJustDecodeBounds = true;
android.graphics.Bitmap bmp = android.graphics.BitmapFactory.decodeFile(imageFilePath, bmpFactoryOptions);
int heightRatio = (int) Math.ceil(bmpFactoryOptions.outHeight / (float) height);
int widthRatio = (int) Math.ceil(bmpFactoryOptions.outWidth / (float) width);
println("HEIGHTRATIO: " + heightRatio);
println("WIDTHRATIO: " + widthRatio);
// If both of the ratios are greater than 1, one of the sides of // the image is greater than the screen
if (heightRatio > 1 && widthRatio > 1) {
if (heightRatio > widthRatio) {
// Height ratio is larger, scale according to it
bmpFactoryOptions.inSampleSize = heightRatio;
} else {
// Width ratio is larger, scale according to it
bmpFactoryOptions.inSampleSize = widthRatio;
}
}
// Decode it for real
bmpFactoryOptions.inJustDecodeBounds = false;
bmp = android.graphics.BitmapFactory.decodeFile(imageFilePath, bmpFactoryOptions);
java.io.File newImageFile = new java.io.File(newImageFilePath);
android.net.Uri newImageUri = android.net.Uri.fromFile(newImageFile);
OutputStream imageFileOS = getContentResolver().openOutputStream(newImageUri);
bmp.compress(android.graphics.Bitmap.CompressFormat.JPEG, 90, imageFileOS);
println("Resized image, wrote out to: " + newImageFile.getAbsolutePath());
} catch (Exception e) {
println(e.toString());
e.printStackTrace();
}
}
For instance, if I had a camera image on the SD card called dottie.jpg and I wanted make it smaller I would do the following:
PImage theImage;
void setup() {
// If the image is too big, you need to make it smaller before you can load it.
resizeImage(android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + "/dottie.jpg", android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + "/dottie_small.jpg");
theImage = loadImage(android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + "/dottie_small.jpg");
}
Homework Due March 5
Make an app that allows the user to manipulate and save a photo.
Read Chapter 15 in Learning Processing: https://getit.library.nyu.edu/go/3962696
Do the exercises: http://www.learningprocessing.com/exercises/chapter-15/
Pixels
In Processing we can access the pixels of an image or those that are displayed on the screen. When accessing them we can pull out the color values and modify it for display.
Here is a quick example that we’ll review:
// Don't forget WRITE_EXTERNAL_STORAGE
PImage theImage;
void setup() {
//size(400,400);
theImage = loadImage("dottie.jpg");
}
void draw() {
loadPixels();
theImage.loadPixels();
// Loop through the x
for (int x = 0; x < theImage.width && x < width; x++ ) {
// For each x, loop through the y
for (int y = 0; y < theImage.height && y < height; y++ ) {
// Calculate the array pixel location for the image
int imageIndex = x + y*theImage.width;
// Calculate the array pixel location for the screen
int screenIndex = x + y*width;
// Get the red, green and blue values from image
float r = red (theImage.pixels[imageIndex]);
float g = green (theImage.pixels[imageIndex]);
float b = blue (theImage.pixels[imageIndex]);
// The closer the pixel is to the center, the lower the distance
float distance = dist(x, y, theImage.width/2, theImage.height/2);
float maxDistance = sqrt(sq(theImage.width) + sq(theImage.height));
float distanceRatio = distance/maxDistance;
// We want closer pixels to be brighter
r = r*(1-distanceRatio);
g = g*(1-distanceRatio);
b = b*(1-distanceRatio);
// We also want sepia
r = r + 99;
g = g + 66;
b = b + 33;
// Constrain RGB to between 0-255
r = constrain(r, 0, 255);
g = constrain(g, 0, 255);
b = constrain(b, 0, 255);
// Make a new color out of the new RGB values and set the pixels of the sketch
color c = color(r, g, b);
pixels[screenIndex] = c;
}
}
// Call updatePixels to tell processing to draw the pixel values to the screen
updatePixels();
filter(BLUR, 2);
}
void mousePressed() {
// Save output to the SD card
save(android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + "/output.tif");
}
Select an Existing Image
We can create an Intent that allows the user to select an existing image using the built-in capabilities and display that image in our sketch.
Intent choosePictureIntent = new Intent(Intent.ACTION_PICK,␣ android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
Here is an example:
final int CHOOSE_PICTURE = 0;
String imageFilePath;
PImage selectedImage;
void setup() {
}
void draw() {
if (selectedImage != null) {
image(selectedImage,0,0,width,height);
}
}
void mousePressed() {
android.content.Intent choosePictureIntent = new android.content.Intent(android.content.Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(choosePictureIntent, CHOOSE_PICTURE);
}
protected void onActivityResult(int requestCode, int resultCode, android.content.Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if (resultCode == RESULT_OK) {
android.net.Uri imageFileUri = intent.getData();
// This Uri is a "content://" style intent which Processing can't use directly. We need to query the MediaStore to get the file path
//println(imageFileUri.toString());
// content://media/external/images/media/9397
String[] columns = { android.provider.MediaStore.Images.Media.DATA }; // The file path
android.database.Cursor cursor = managedQuery(imageFileUri, columns, null, null, null);
if (cursor.moveToFirst()) {
imageFilePath = cursor.getString(cursor.getColumnIndexOrThrow(android.provider.MediaStore.Images.Media.DATA));
println(imageFilePath);
selectedImage = loadImage(imageFilePath);
}
}
}


