D7C_1143.jpgStarting to feel an itch from not having a photo shoot for a while, I got my girlfriend to do some posing for me, again. Mostly so I could do some quick lighting tests. See if my thoughts worked when put out into practice. I haven’t quite decided on that yet, but I do feel that I got some of it right.

I started out by trying to bounce a single light on the wall behind her, to get a specular highlight that would be as a halo around her head, but I think my light was too soft, and my wall not shiny enough, so it didn’t turn out as planned. Single Nikon SB-800 speed light on a stand, with a 60″ umbrella, to the right of the camera, and a bit up. Pointing at the wall.

The whole idea for the setup was from the amazing Strobist blog, of course. And I will give it another go, I think. With a much smaller umbrella. Might be easier.

And also see if I don’t have a wall somewhere that is a bit more shiny. Could also maybe hang something on the wall, to make it more shiny.

D7C_1186.jpg Next I was just going for some basic butterfly lighting. So I had the one umbrella straight on, horizontal, and high up, pointing down on her, but very close. And I also had her hold a reflector, to get some light back up. For some added effect I also placed a strobe on the floor behind her chair, with a red gel on it.

I don’t think the reflector worked as good as I wished it had, so I will also give this another go, but use both strobes in front over her instead, with each its own umbrella.

You can see more pictures from the shoot at flickr.

This weekend Dark City had two days of concerts, as an official club scene for the PStereo festival in Trondheim.

The bands represented a mixture of genres, but all of them had some elements of electronic sounds to them.

We Are Monsters performing live.Starting off on Friday was We Are Monsters (NO). A highly electronic and funky duo, which also incorporates guitar in their music. They kicked off the whole mini festival with a really nice sound, and set a really good mood for what was coming.

Not the most interesting band to photograph, but they were not in any way bad, and I believe I got a couple of good shots at least.

It always helps to like the music, and in this case I did. I had seen a couple of youtube-videos before, but they did in no way justice to how the band sounded. I will keep my ears open to what is to come from We Are Monsters.

Designer SubstanceNext up was Designer Substance (NO). They were also a duo at this time, and also a local band, but they were, however, purely and electronic band. From what I heard, they used to have vocals, but to be able to do a bit more improvisation to their set, and not just play off backing tracks, they had instead opted to use samples for the vocal parts.

The set they delivered was hard kicking, and had the crowd really warmed up. The floor in front of the stage was nicely packed, and constantly moving to the beats.

It was also very easy to see that there were a lot of friends in the audience, something that is to be expected with local bands, but which also is one of the good things about having them play.

The sound was great, and it really seemed like they worked well together on stage, though the live set would probably have been better as an act with a dance floor, more than a regular stage. Nothing wrong with that, since it really is not easy to have a great live show when all members are standing behind their laptops. Of course it can be compensated for with some visual elements on a big screen, or amazing lights or lasers or anything, but that is something that I do not expect in a club like this.

It was great to see them, never the less, and I will also have them on my “to watch out for”-list in the future.

Last band on Friday was also the band I was looking most forward to, Code 64 (SE/NO). This was also the only band I had seen play live before. Both times at Elektrostat, but with two different singers. Code 64 And having a singer really adds to the act when playing live.

This band filled the floor.

Being this was the third time I’d see them live, and remembering the previous concert well, and as a great one, my expectations were high. And also since this would be the smallest stage, it would be interesting.

I was NOT disappointed.

From the first song the mood was up to the roof, and it never slowed down during their one hour set.

Bjørn (singer) really gave what he had, and worked the crowd. And the size of the venue really didn’t matter. Everyone was moving, and people were singing along. And the whole thing was super fun when Hasse and Cricke joined Bjørn at the front of the stage, dancing to the second to last song, before they kicked off an unplanned extra number. I think everyone in the crowd was happy with that performance, and the end of the first day.

Spring CollectionThe first off the four bands that played Saturday was a local band called Spring Collection. A very energetic experimental duo, that played really loud. I don’t think that the small stage did them justice, though, and would probably have worked a lot better with a lot more room. The sound was much bigger than the small basement of Café 3B. The crowd on Saturday was also a bit more sparse than the day before, and I think that also softened the impression you got. Not that it seemed to slow the band down in anyway. They were fun, and I will see them again if I get the opportunity. Something I have no doubt I will have, if I am to consider their playing schedule on myspace.

The Maladronia Institute Taking on the crowd next was the weekends biggest band, at least in numbers. The Maladronia Institute filled the stage to the max with their five person line-up.

This band was my biggest surprise this weekend, as I had no knowledge of their sound, but hearing them was most pleasing, as I felt like it was a mixture of Tool, Motorpsycho and Seigmenn, which all are bands I really enjoy.

But even though they had were large in numbers, on a small stage, they did not seem out of place. They delivered a fantastic set, and they sounded great. Really looking forward to hear more from this band, and see them again.

EverfearEverfear was the one band for the weekend that I was really skeptical about, and also the one band I probably won’t listen to after. Not at all fitting with my taste.

There is, however, nothing bad to say about their stage performance. The energy was top notch, and they really looked like they had played live before. And they probably know what they are doing, but I really can’t tell, since their style of music sound more like a joke to me, than anything else. But then again, so does many genres.

Violent Work of ArtFinishing off the second and last day off our little festival, was the Swedish band Violent Work of Art. The only band that had that had a female member.

As with Code 64, my expectations were high, even though I didn’t know much about them from before, but I had heard they were great, and so they were.

Their image really fit their great synth/industrial sound. And the had great energy on stage. The only sad thing was that there could have been more people seeing them.

They had driven over a thousand kilometers from south in Sweden, to play in our little club in Trondheim, and those who weren’t there for the show really missed out.

Together with Code 64 and The Maladronia Institue, Violent Work of Art was among my favorites this weekend.

As for the pictures from the weekend I must say I am still not a very good friend with LED stage lighting, but I think that a lot of the problems is with the setup, and that the lighting guys aren’t working that full time. Not that they in any way were bad, but I guess stage lights aren’t made for photographers, and so I am not prioritized.

I do feel I did get some good shots, and the bands I’ve heard from seems like they were satisfied, so I will just keep at it.You can see all the photos that made the cut over at flickr.

From a festival organizers point of view, I would really like to thank all the bands that came and played for us, delivering great shows. I would also like to thank the people that came, and witness the performances. I really hope everyone had a great time. And, of course, a big thanks to the rest of the Dark City crew, and to Café 3B for making the whole weekend what it turned out to be.

Just sharing a couple of shots from the latest We Were Lightning concert in Oslo (August 2010). As usual I had my camera, and took some photos.

I’ve felt that I have done better work, but there are a couple here that didn’t turn out all that bad.

D7C_0354.jpg

The lighting wasn’t great, and it was a bit awkward to shoot. It wasn’t too much room in front of the stage, and so I couldn’t stay very stable.

The next one is definitively not my best shot, but I do like it when I can get a shot of the drummer, since drummers are usually a bit neglected in concert photography.

D7C_0416.jpg

D7C_0421.jpg

D7C_0522.jpg

Head on over to the set at flickr if you want to catch the rest.

I recently read the book Aarons code, and with that the thought of writing some contour tracing functions came up. When I also, a few days later got an idea for a project, I got to it. Do searches on Google pointed me in the direction of the blob extraction algorithm that OpenCV uses, and so I found “A linear-time component labeling algorithm using contour tracing technique”.

Lately I have also started looking into using NetBeans as an IDE for programming with the Processing library, so I decided that I would implement the algorithm in the paper in java, using Processing.

The code is provided below, and is provided as is. It can probably be optimized a bit, and/or rewritten to be better. But for now it works for me.

If you have any suggestions to changes, or you use it, please leave a comment so I can check it out.

 /*
 * An implementation of
 * «A linear-time component labeling algorithm using contour tracing technique»
 * by Fu Chang, Chun-Jen Chen, and Chi-Jen Lu
 *
 * Written in Java for use with the Processing (www.processing.org) library.
 *
 * Code written by Greger Stolt Nilsen
 * (gregersn@gmail.com / http://gregerstoltnilsen.net)
 * Copyright 2010, Greger Stolt Nilsen
 *
 * Code is provided «as is», and no warrenty is given. Use at your own risk.
 *
 * This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

 */
/*
 * Create a new instance with:
 * ComponentFinder finder = new ComponentFinder(this, image);
 * where "image" is the PImage (or PGraphics) to be traced.
 * use the find()-function, to get all the contours in the contours arraylist.
 * Each contour is by itself an ArrayList of PVectors.
 *
 * render_blobs() will return a PImage object that is a rendering of all the
 * blobs in the traced image.
 *
 * The Image to be traced need to be black (0x000000) objects on white background.
 * So use the threshold-filter to get to that.
 *
 * Also, unless the outer border of pixles is white, the finder will hang.
 */

package ComponentFinder;

import processing.core.*;
import java.util.ArrayList;

public class ComponentFinder
{
    PApplet parent;
    public ArrayList contours;
    int[] inout;
    int[] L;
    PImage I;
    int C;

    // An array with the 8 direction coordinates (x1, y1, x2, y2... x8, y8)
    int cd[] = {1, 0, 1, 1, 0, 1, -1, 1, -1, 0, -1, -1, 0, -1, 1, -1 };

    public ComponentFinder(PApplet p, PImage img)
    {
	parent = p;
	I = img;
	C = 1;
	L = new int[I.width*I.height];

    }

    int getNumContours()
    {
	if(contours != null)
	    return contours.size();
	else return 0;
    }

    public int find()
    {
		// Initialize the blob map to zero.
		for(int i = 0; i < I.width*I.height; i++)
		{
		    L[i] = 0;
		}

		// Make a new array list to store each contour.
		contours = new ArrayList();

		C = 1;

		int pos = I.width; // Start analyzing the image at the second line

		I.loadPixels();

		// Label the first line as blank pixels.
		for(int x = 0; x < I.width; x++)
		    L[x] = -1;

		for(int y = 1; y < I.height; y++)
		{
		    for(int x = 0; x < I.width; x++)
		    {
			if(L[pos] == 0) // Only process unlabeled pixels
			{
			    if(((I.pixels[pos]&0xffffff) != 0x000000))
			    {
				// White pixel
				L[pos] = -1;
			    }
			    else if(((I.pixels[pos]&0xffffff) == 0x000000))
			    {
				if((I.pixels[pos-I.width]&0xffffff) != 0x000000)
				{
				    // If the pixel above is a white pixel,
				    // then this is the start of an outer contour
				    L[pos] = C;
				    // Start tracing an outer contour
				    contours.add(contourTrace(new PVector(x, y), 0, C));
				    C++;
				}
				if(((I.pixels[pos+I.width]&0xffffff) != 0x000000) && (L[pos+I.width] == 0))
				{
				    // If the pixel below is a white pixel, then it is the start of an
				    // inner contour, and we get the id for the outer contour
				    // then start tracing the inner contour
					int l;
					if(L[pos] != 0 ) l = L[pos];
					else l  = L[pos-1];

					if(L[pos] != 0) L[pos] = l;
				        contours.add(contourTrace(new PVector(x, y), 1, l));
				}
				if(L[pos] == 0) if(L[pos-1] > 0) L[pos] = L[pos-1];
			    }
			}
			pos++;
		}
	}
	I.updatePixels();
	return getNumContours();
    }

    // Traces a countour at the given pixel S,
    // r is set to 0 for outer contours, and 1 for inner contours.
    // c is the label to give the contour
    ArrayList contourTrace(PVector S, int r, int c)
    {
	int next = 8;
	ArrayList cont = new ArrayList(32);
	PVector current = new PVector();
	cont.add(S.get());
	if(r == 0) // Outer contour
	    next = Trace((PVector)cont.get(cont.size()-1), 7, c);
	else if(r == 1) // Inner contour
	    next = Trace((PVector)cont.get(cont.size()-1), 3, c);

	if(next == 8) return cont; // The pixel is isolated.

	PVector T = new PVector(S.x + cd[next<<1], S.y + cd[(next<<1)+1]);
	cont.add(T.get());

	next = Trace((PVector)cont.get(cont.size()-1), (next+6)%8, c);

	if(next == 8) return cont;

	while(true)
	{

	    current.x = (float)((PVector)cont.get(cont.size()-1)).x + cd[(next<<1)%16];
	     current.y = (float)((PVector)cont.get(cont.size()-1)).y + cd[((next<<1)+1)%16];
		next = Trace(current, (next+6)%8, c);

		// Check if we are back at start position
	    if((current.x == S.x) && (current.y == S.y) && (current.x + cd[next<<1] == T.x) && (current.y + cd[(next<<1)+1] == T.y))
	    {
		return cont;
	    }
	    else
	    {
		cont.add(current.get());
	    }
	}
    }

    int Trace(PVector P, int n, int c)
    {
		for(int i = 0; i < 8; i++)
		{
		    // if pixel at position n+i is black, return n+i
		    PVector ni = new PVector(P.x+cd[((i+n)%8)*2],
					    P.y+cd[((i+n)%8)*2+1]);

			if((I.pixels[(int)(ni.y)*I.width+(int)(ni.x)]&0xffffff) == 0x000000)
		    {

				L[(int)(ni.y)*I.width+(int)(ni.x)] = c;
				return (i+n)%8;
		    }
		    // if not, mark with a negative number
		    else
		    {
				if(L[(int)(ni.y)*I.width+(int)(ni.x)] == 0)
				    L[(int)(ni.y)*I.width+(int)(ni.x)] = -1;
		    }
		}
		return 8; // Should only happen for isolated pixels.
    }

    public PImage render_blobs()
    {
		PImage blobs = parent.createImage(I.width, I.height, PApplet.RGB);
		blobs.loadPixels();
		parent.colorMode(PApplet.HSB);
		for(int i = 0; i < L.length; i++)
		{
		    if(L[i] > 0)
				blobs.pixels[i] = parent.color(PApplet.map(L[i], 1, C, 0, 255), 255, 255);//|0xff000000;
		    if(L[i] == -1)
				blobs.pixels[i] = parent.color(0, 0, 255);
		    if(L[i] == -2)
				blobs.pixels[i] = parent.color(0, 0, 0);
		    if(L[i] == 0)
				blobs.pixels[i] = parent.color(0, 0, 128);
		}
		blobs.updatePixels();
		return blobs;

    }
}

I’ve had an old Viscount c.100 transistor organ standing around in my
studio for quite a while, and I’ve finally come around to start gutting
it. The goal is to learn a bit more about electronics, as well as try to
be able to use the spring reverb, the rhythm generator and the pedals
for something else.

D7C_9061.jpg

What I am thinking with the reverb is to put it in it’s own box, so that
it can be used as an insert effect on mixers, or as a pedal effect for
guitar.

The rhythm section can be used for what it is for, but I want to build
it into a smaller box, so it is portable and can be used in different
situations. Also, since I have figured out it gates the bass pedals, I
will try and add connections so it can be used as a trigger/gate for
other stuff.

The pedals I will build into a box, with the oscillators so that it can
be used on it’s own as a foot driven bass keyboard for live performances.

I am self thought when it comes to electronics, and I have not studied
it very well, but I do know some basics. So this is a challenge, but a
good one.

In lack of a proper oscilloscope I am using xoscope with a sound card probe.

More pictures, and some sketches will come when I figure out something
useful, and have organized my notes.

I do most of my photo editing, and picture organizing, in Adobe Photoshop Lightroom. Since I now how over forty thousand pictures from miscellanous events and concerts, and everything else, I like to tag people in pictures, so I can find them again, easily, if anyone asks.

Picasa 3 came with a face detection feature, which scans through all the pictures in your library, and tries to find people with some fancy algorithm. You can then add a name to the face, and easily see all pictures you have with that person in it. Almost. It doesn’t find a face in every situation, so it is not perfect, but it is a good start.

However, Picasa does not store the data about people in the files metadata. You can trick it in there, but since I work with RAW files (NEF), and Picasa doesn’t use XMP for metadata, that is not a good way to do it.

With a bit of reasearch, I found out that in every directory where there are pictures with found faces, Picasa stores a file ( .picasa.ini) that contains information about what picture file contains faces, where in the file there is a face, and what contact that is hooked up to. Picasa also stores an XML file with all the contacts in them.

Using that I wrote a small Perl-script that gets all the contacts out of the XML-file, scans through the current directory for the .picasa.ini file, matches contacts with that, and stores the new data in XML metadata with the file.

Before using the script, you need to change some variables to point to the right contacts file and such. You also need the XML library for Perl, and the Perl Exiftool-library installed.

The script has only been tested in Windows 7, with Cygwin.

The procedure goes as follow:

  1. In Picasa, do the face tagging. Check the picasa website for help on that.
  2. In Lightroom, make sure you select all the pictures you want to update, and write all the metadata to files. That’s from the metadata menu.
  3. Go to the folder you have some pictures with people in it and run the Perl script.
  4. Open Lightroom again, select the pictures, and choose to read metadata from files.

It seems to be working okay now, but I take no responsibility for damages it may do to your pictures if you try it. Make sure you have a backup first!

To run the script recursively I use the command:

 find . -name \.picasa\.ini -execdir ~/scriptlocation/faceextract.pl \;

faceextract.pl

#!/bin/perl -w
#
use strict;
use utf8;
use XML::Simple qw(:strict);
use Data::Dumper;
use Image::ExifTool qw(:Public);

if(scalar(@ARGV) == 1)
{
 chdir($ARGV[0]);
}

# Location of contact file
my $contactsfile = "/cygdrive/c/Users/greger/AppData/Local/Google/Picasa2/contacts/contacts.xml";

# Picasa-file-filename
my $filename = ".picasa.ini";

my $xml = new XML::Simple ( ForceArray => 1);
my $xmpinfo;

# Parse the contacts file, and make a contact map
my $contacts = $xml->XMLin($contactsfile, ForceArray=>1, KeyAttr =>{}, );
my %contactmap = ();
my $conts = $contacts->{contact};
foreach my $contact (@$conts)
{
 $contactmap{$contact->{id}} = $contact->{name};
}

# Open and read the picasa file into an array
open(PICASAFILE, $filename) || die("Could noe open picasafile");
my @picasadata = <PICASAFILE>;
close(PICASAFILE);

# Remove all carriage returns.
foreach my $line (@picasadata)
{
 $line =~ s/\r\n/\n/;
}

# Go through the picasa file
for(my $i = 0; $i < scalar(@picasadata); $i++)
{
 if($picasadata[$i] =~ /^\[(.*)\]/)
 {
 my $exifTool = new Image::ExifTool();
 print $1."\n";
 my $xmpfile = $1;
 if($xmpfile =~ m/NEF/i)
 {
 $xmpfile =~ s/NEF/xmp/gi;
 }
 print "Using $xmpfile for info.\n";
 $exifTool->Options(List => 1);
 $xmpinfo = $exifTool->ImageInfo($xmpfile);

 my $Subjects = $exifTool->GetValue('Subject');
 my $Hierarchical = $exifTool->GetValue('HierarchicalSubject');

 $i++;
 my $changes = 0;
 if($picasadata[$i] =~ /^faces=(.*)/)
 {
 my @faces = split(/;/, $1);
 print "\tFound ".scalar(@faces)." faces\n";
 foreach my $face (@faces)
 {
 my ($region, $id) = split(/,/, $face);
 my $new_subject = $contactmap{$id};
 print "\t\tFound: ".$new_subject."\n";
 my $old = 0;
 if(ref($Subjects) eq "ARRAY")
 {
 for my $subject (@$Subjects)
 {
 if($subject eq $new_subject)
 {
 $old = 1;
 }
 }
 }
 elsif(ref($Subjects) eq "SCALAR")
 {
 if($$Subjects eq $new_subject)
 {
 $old = 1;
 }

 }
 if(!$old)
 {
 $exifTool->SetNewValue(Subject => $new_subject, AddValue=>1);
 print "Added to keywords.\n";
 $changes++;
 }

 $old = 0;
 #print Dumper($Hierarchical);
 if(ref($Hierarchical) eq "ARRAY")
 {
 for my $subject (@$Hierarchical)
 {
 if($subject eq ("People|Persons|".$new_subject))
 {
 $old = 1;
 }
 }
 }
 elsif(ref($Hierarchical) eq "SCALAR")
 {
 if($$Hierarchical eq ("People|Persons|".$new_subject))
 {
 $old = 1;
 }
 }

 if(!$old)
 {
 $exifTool->SetNewValue(HierarchicalSubject => ("People|Persons|".$new_subject), AddValue=>1);
 print "Added to hierarchical keywords.\n";
 $changes++;
 }

 }
 }
#        $changes = 0;
 if($changes > 0)
 {
 my $ret = $exifTool->WriteInfo($xmpfile);
 if($ret == 1) { print "\tFile written ok.\n"; }
 if($ret == 2) { print "\tFile written, no changes.\n"; } #Should not happen
 if($ret == 0) { print "\t *** File write error on file: ".$xmpfile." ***\n"; }
 }
 else
 {
 print "\tNo changes to file.\n";
 }
 }
 print "\n";

}
© 2010 Greger's blog Suffusion WordPress theme by Sayontan Sinha