Archive

Archive for July, 2009

Yar, the Seadragon be close

July 31st, 2009 admin No comments

…. Man I’m lame.

Microsoft’s “Seadragon” seems to finally be ready, or at least it’s ready for public beta. The idea is you can quickly load, view, and zoom-in on extremely large images. The image you see below is something I quickly ginned up, it’s 4500×4500 pixels, about a 4mb image. The tech. isn’t anything new, Google maps does something similar with a granularity of images but this one seems a bit more seamless. Anyways take a look at the photo below and enjoy.

Categories: Uncategorized Tags:

Youtube hates me

July 29th, 2009 admin No comments

Youtube has something against my search for “late goodnight”, well to hell with you youtube.

Actual Error:

500 Internal Server Error

Sorry, something went wrong.

A team of highly trained monkeys has been dispatched to deal with this situation.

Also, please include the following information in your error report:

Gu8S_7hWmr7JEnfc9nZzE40XMHDiZ6BzLjncn9og2tFCHXf_TEtlquz9W23p
PrFSd0IKCAgiK4D7HDpRz1bqbu41ZKKuO1ekOJU1fIqVdCsyZiov56FRJzMu
cAu3NlVeUEO64xXfJYU3jBOYCrFIX9Zby6UMlGJ8yE3Jx8BAHxo-p3ehaPl-
ooXHkcWpx4hh472nNWbkyk5LfX3RgTziDG_Em9h3b0isUnehTfCxZRpocJ_6
4sKNDn8M16xINKre73poea0kJTEEuiileproT6lrseLU-HpvyPBrEqrP5qeY
aurKNBkj2wgXD4dP7yOu2iGrvdQRfyYDnd6jxHhrPzDusapCXFEHIfdpxR1W
XIsUOxEEX-t5663RmTTEd8Z7UNoeRqfrOzqXyCTxP680O6vpJDGRedlCpxXp
ISqxD_g4Rz3ti9x4ROT9_NVibh5b2PBmcBQYQcBZxhMWcxx3kIfQp0_ghl4j
YlMGpE3_CNHo3bHwb7qHr-rhQUiDfhuEB6-huCTF49xZIicczN6WHEzLy4AQ
frxsyddf0pDnvFtpyZGvqoRYcCCIweevx4QJGUhC10NMQSU-U1vVYCf0B66G
Q1tgxQLnTG10WU-YOWGWBB4cnuYvQ5WrhdgUTHypUnqu19eDzIaGW-JDLPQQ
nATZXOp7RhL4z-FooXFc3OguVAgoTxw3-Xc_Am8fBO5wd6H8e6p6DrMksKKy
6HmkhqlYOTC7YqwqnQqzvjbfE4XYKCv0w3EdWKGcVgD4A99cNQg46voiHgTM
g6JMkmcrq5yzgEnBiDcTx10L0Dy81VmSeja92UbZ0BhM6FCNtF3QhZmytJHD
duyVfKWaB20iNKJdR-2vSdAZlVaV9qgjV5Y1viMgNCrjkMFPwopVD_P-u7ia
FFxCVsTFnDYVJBlNH-08dCMzpovStp-XImOin1twpr0j-mix0Ex4SRqpZKKK
euK6YF3QzqUAo7z9zOAFI5AFWfQHABeDh95L1oW9gcPoiU5vqvzBjbJNxdS2
aWfbqKinzLaVDsurNiZwx59PsQEHJzjzM0MD_coHLW3gTnz7_fFbYCBUQIkk
quiNJBYk047XAgTd2h5uSjuYm-SQ4UoT7uhH6wxE73eys2usmRpISE0gIqUP
O7oooNmpYGXrb9TQIseBtjSMoh4OKFW_1OA2MOgEAuuJrkRXTpzVclLNVTDd
suyr-CraU_bXj_MKFRvnEf2Spw08mcUFnD0ReKqDdUPcKpfnK4AQir_Iq1Im
HgRk6jBaLhgwIezccech5LtzkJLmNz1Y_GtE-svap_AV33Zo3Svi9t2kULsw
KZX0hYqY9u0LoNW-eQr-KoCDcQ_9Zmi7MM_DlUpq8-lLwelgA-D05UNtaddi
USu2dz4TRKu4x_iJaAgY4ElOLpc0V04e8WKJoUGMjK2fbCwvvAZC04AxJVTg
fTh6mVWD9j24m-ixdrGaTsYxiSIYnziH3y0bYDwaZJ-p2tj_OZ2oU3bnhkdn
Qeu_XvVa4a8gg-FX0cB-g-Tg9af_3gzG-CnZEBK3rcNCmPL5-rH4x20IgcWS
v_-FYTnwU-xWHKgalVpjJKBXMFKm0j8Wlaq9IxG4pMYKIJnp0G5svKw6QxlK
iDd0MKIcb1r-7iagrkzFRtKwW4MHwuGmXGeL8ao42h2bcD4Y3VjaQSyzeSZh
wBZR7BoAlkrugNn01WUZ2YlWg2pvCvB63NfnEe99IkBDV6oYr-JrhuxH1dzu
JvVsdnXdgMaMM7TtPL7C1ZekwHLvDrEsPGxESjHUBUEbuliVDfOHL3DjHnAh
m5KlJq_q87D0Z8cvEcqOhZyoPeUr_RrQxprM80TmpOYjPiYGG0PJSE_5GRWW
nP9Ffch5_849n88rqbjPrulJkCdnDqRYoURVwxYp8yUsbhKn7lQBPuMyqbQE
vKlA2UqKvSY2Jqlj3w9LbkDd9mkSycBG3yrpArXri9VH1vWT9d_smLTKsdP_
n7qYpJf73xDujWZxskudL9YkvJdvtykCZlkHxiALjXrCQ0ej41JpptO04Bbw
clvU313nXx_wDHMe51-dWZDsxEbk5XNxsdl4-wrfGvaDwP_mKMd7r8cPIook
WpQWNbtQBx8GMFoenJXzEfaYtuj1rkONSUdjUUiATu4Miy8u-sWHfiDNjb7Y
zzW3cRowqr4i95i-vEbtaPXhF8M8ZRD0Xs_YLrWLHrYcD3MfdX_CnUBjlzJa
TZD7a2gB-lTYhN5Ihb9Z8fFFYzICqxUwm_A671hTFYmjFaoPyN8sF42wIRKz
fCPRtS-vmlHoqjEzRO_qvo8MGvLlmm1r2bIMktP8DJEhy4eeTYFOqh5l2kVH
HS-gHD_dYbEJoAxaoN_iAeGg_mpwQ97NJJuOk2FMmMu3r7GPGUCOherkLJDX
uwZrpdCyERcf1rowsA90grAQcg7KpZKRIXwExH1JhfkKoD2kKn1vKheQlBfh
t32ZXevZK1zW8hUSS8oUnikuy2bwtlvnlFr5qr7Gid_I0R4tVNnnYZZ6a2MD
kx8oT2o7pSO1QjL3vmDbgFiOiY_izEtx2eTdCCbY07VyIa6tp5bVW9JrxvLv
dB3vX6sG_MBFPw7SHVvXyIU02eqfCob9Kji7je0DcDkOTBaxl27xrItlk71-
WPL3Dg6DBy4agogdbwX3hBinbSsBJVjgXvf85Lpt8Ggw6fJ-6dPG1z5bre2B
xM7M97tX-vAGjMiWeMOCpsOOptKsX2H5AC-RFmbhicCkvYtk0PfH5PRGhQt3
dnSkTEVjpJ9qk8eYd5yrVrIjnq0Mx5tEzxY=
Categories: Uncategorized Tags:

Old Code

July 28th, 2009 admin No comments

[preamble]

Going back to old source code can be both a blessing and a curse. (If you want to get to the computer vision code  just scroll past my preamble)

The negatives:

  1. Can be hard to read
  2. Logic might not make sense any more
  3. Out of date
  4. Embarrassing, as in it’s embarrassing how bad you might have been.

The positives:

  1. Reusable code can speed up new projects
  2. Nostalgia.  “Aw look at that 10 level deep if/then nest.  Isn’t it cute.”  **Also a negative
  3. Ego boost.  Typically you don’t remember really old projects all that well, it’s sometimes surprising to find you aren’t as bad as you’d originally thought

[/preamble]

What’s my point?  No point really, I just found some old computer vision code that I thought I’d post.  The following code makes use of the CImg 1.3.0 library.

Code to convert images to luminance:

template <class T>
cimg_library::CImg<T> luminancei(const cimg_library::CImg<T> &img){
	CImg<T> ret(img.dimx(),img.dimy(),1,3);
	double lum_thresh[3] = {0.60f,0.30f,0.10f};
	int i,k;
 
	for(i=0;i<img.dimx();i++){
		for(k=0;k<img.dimy();k++){
			ret(i,k,0) = ret(i,k,1) = ret(i,k,2)= (img(i,k,0)*lum_thresh[0] + img(i,k,1)*lum_thresh[1] + img(i,k,2)*lum_thresh[2]);  
		}
	}
	return ret;
};

Prewitt Edge Detection(on grayscale images only):

static float My[3][3],Mx[3][3]; //Global Filters
 
void set_mx(float ar[]){
	/*set mx from 1D array*/
	int r,c,ar_idx=0;
	for(r=0;r<3;r++){
		for(c=0;c<3;c++){
			Mx[c][r] = ar[ar_idx++];
		}
	}
}
void EdgeDetection::set_my(float ar[]){
	/*set my from 1D array*/
	int r,c,ar_idx=0;
	for(r=0;r<3;r++){
		for(c=0;c<3;c++){
			My[c][r] = ar[ar_idx++];
		}
	}
}
//Apply filters to grayscale image.
CImg<unsigned char> apply(const CImg<unsigned char> &img, int complexity/*=0*/) {
	CImg<unsigned char> ret(img.dimx(),img.dimy(),1,3);
 
 
	int r,c;
	int dx,dy;
	int dx_dy;
 
	/*main loop := apply Mx and My to input image.*/
	cimg_forXY(img,x,y){
		dx = dy = 0;
 
		if(x == 0 || x == img.dimx()-1) dx_dy = 0;
		else if(y == 0 || y == img.dimy()-1) dx_dy = 0;
		else {
			/*dx*/
			for(r = -1; r < 2; r++){
				for(c = -1; c < 2; c++){
					dx += img(x+c,y+r,0) * Mx[r+1][c+1];
				}
			}
			/*dy*/
			for(r = -1; r < 2; r++){
				for(c = -1; c < 2; c++){
					dy += img(x+c,y+r,0) * My[r+1][c+1];
				}
			}
			/*Complexity.   0:=Approximation  | 1-Inf:=No approximation*/
			if(complexity == 0) {
				dx_dy = abs(dx) + abs(dy);
			}
			else {
				dx_dy = (dx * dx) + (dy * dy);
				dx_dy = sqrt((float)(dx_dy));
			}
			/*some values exceed range of 0-255, clamp these down.*/
			if(dx_dy > 255) dx_dy = 255;
			if(dx_dy < 0) dx_dy = 0;
		}
		/*invert colors to make nicer output*/
		//ret(x,y,0) = ret(x,y,1) = ret(x,y,2) = 255 - sum;
		ret(x,y,0) = ret(x,y,1) = ret(x,y,2) = dx_dy;
	}
	return ret;
}
/*
prewitt()
input := 
	const CImg<unsigned char> &img - Constant address to an image file.
	int complexity - Complexity sets whether we use full sqrt(dx^2 + dy^2) or simply an approximation.
					Note:  Any non-zero value for complexity results on the more complex solution
output := 
	CImg<unsigned char> - Image with prewitt edge detection applied.
descrip := prewitt() applies edge detection based on the prewitt masks.
*/
CImg<unsigned char> prewitt(const CImg<unsigned char> &img,int complexity/* = 0*/){
	float mx[9] = {-1,0,1,\
				   -1,0,1,\
				   -1,0,1};
	float my[9] = {-1,-1,-1,\
					0,0,0,\
					1,1,1};
	set_mx(mx);
	set_my(my);
 
	CImg<unsigned char> ret = apply(img,complexity);
	return ret;
}
void example_usage(char *image){
     CImg<unsigned char> ret(image);
     ret = luminancei(ret);
     for(int i = 0; i < 5; i++) ret = prewitt(ret);
}

Easy peasy, but what if your image is noisy?(Most are and only artificial images have clean backgrounds.)

Simple, blur the image first then apply the edge detection:

double gaussian(int x, int y, float d){
	double x2 = x*x;
	double y2 = y*y;
	double d2 = d*d;
	double val = -1*((x2+y2)/(2*d2));
	double denom = 2*3.14159264*(d*d);
	return std::exp(val)/denom;
}
CImg<unsigned char> gaussian_blur(const CImg<unsigned char> &img, int delta, int range){
	CImg<unsigned char> ret(img.dimx(),img.dimy(),1,3);
	int gauss[5][5];
	int r,c;
	/*calculate gaussian filter matrix.
	  Technically 'range(rows/cols)' should be a function of 'delta' but we're approximating here... plus
	  I have no desire to convolve something larger than 5x5.*/
	for(r = -2; r < 3; r++){
		for(c=-2;c < 3;c++){
			gauss[c+2][r+2] = (int)((gaussian(r,c,delta)*273)+0.5);
		}
	}
	double R,G,B;
	int denom;
	cimg_forXY(img,x,y){
		R = G = B = 0;
		denom = 273;
		for(r = -2; r < 3; r++){
			for(c=-2;c < 3;c++){
				if(isinrange(&img,x+c,y+r)){
					R+=gauss[c+2][r+2]*img(x+c,y+r,0);
					G+=gauss[c+2][r+2]*img(x+c,y+r,1);
					B+=gauss[c+2][r+2]*img(x+c,y+r,2);	
				} else {
					denom-=gauss[c+2][r+2];
				}
			}
		}
 
		ret(x,y,0) = R/denom;
		ret(x,y,1) = G/denom;
		ret(x,y,2) = B/denom;
 
	}
	return ret;
}
void example_usage(char *image){
     //First we blur the image 5 times.
     CImg<unsigned char> ret(image);
     for(int i = 0; i < 5; i++) ret = gaussian_blur(ret);
 
     //Convert to gray after blur
     ret = luminancei(ret);
 
     //Now apply the edge detection
     ret = prewitt(ret);
}

In practice I’ve found 4-6 iterations through the filter are good.

torn
*Original

torn_edge_blur
*Edges, No Smoothing

torn_edge_blur
*Edges, Smoothing

Categories: Uncategorized Tags:

Aimbot Stack

July 16th, 2009 admin No comments

plgoldrush0032

Occasionally something happens when I play games that reminds me why I continue to do so.

In an odd bit of ’6-Degrees of Separation’ my brother was trolling the IO web forums and came across this link. IO being a Team Fortress 2 clan.

Anyways whenever anyone complains about a pub stack** I either claim I’m the only human player and the rest of the players are my aimbots or that I’m running a multi-box rig and that I am controlling every player simultaneously. Amusingly it caught on and others in my match named themselves “Aimbot” something or other. I’m the player in the red circle on my version of the screenshot. Pretty funny stuff and kinda weird that my brother stumbled across it and recognized my steam avatar(the blue D&D dice). I don’t know why this tickles my fancy so much.

Too funny.

**
pub stack: When good players align themselves with 1 team instead of spreading their skill, thus stacking a particular side. It is considered a douchey thing to do in public servers.

Categories: Uncategorized Tags:

Ogre3D 3DS Max Lightmap

July 15th, 2009 admin 1 comment

To start you’ll need the following:

  1. Ogre3D
  2. 3DS Max 2010 (Will probably work with 8&9 as well)
  3. 3DS Macro Script MultiUnwrap ***Please see my comments below
  4. 3DS Macro Script Bakersfield (Not required for my tutorial but useful for non ogre lightmapping.)
  5. OgreMax exporter
  6. Content:  I make the assumption you have content or the means to make content.

For a basic tutorial on rendering LightMaps in 3DS Max you should watch the following:

First things first, copy the macro scripts in to the \Autodesk\3ds Max 2010\ui\macroscripts folder.   You’ll then need to open up 3DS Max and select ‘Customize->Customize User Interface’ from the toolbar.  Switch to the ‘Menus’ tab and drag both Bakersfield and multiObjectsUnwrap to whatever menu you wish, I put them under the ‘Rendering’ menu item and will reference them as such.

OgreMax comes with it’s own self installer so that should be easy enough, just make sure you get the right version for your copy of 3DS Max.

There are a few ways to make a LightMap but the 2 I dealt with were per-object LightMaps and per-scene LightMaps.  This tutorial is for creating a single scene map.  I highly recommend using per-scene unless you’ve got an amazing amount of processing power.  My rig chugged under the weight of 40 512×512 lightmaps overlayed on the textures.  I also recommend you save often.

My method isn’t pretty.  I don’t claim to be an artist, this is what worked for me.  In fact I just got it working about an hour ago. There are some little hacks I had to do to get the OgreMax output I required, more on that in a bit.  According to the OgreMax author I wasn’t setting my scene up properly. I don’t necessarily disagree but I did everything by the book and wasn’t getting results.

whole1

Setting Up the Scene:

  1. Open your content.
  2. Highlight all objects in the scene and go to ‘Rendering->multiUnwrap’
    1. In ‘Work On Channel’ select 2
    2. Click ‘unwrap UV’s’ when ready.
    3. Go get some coffee if your scene is big.
  3. The ‘Edit UVW’s’ window should appear, if it doesn’t click on your newly merged object, go to properties, and click ‘Edit’ under ‘Parameters’
    1. edituvw
  4. In the ‘Edit UVW’s’ window select all of the faces and go to Mapping->Flatting Mapping on the menu.
    1. I set ‘Spacing’ to 0 to give it the tightest packing (edit: which it seems is causing some edge problems, I’d recommend some spacing in the pack.)
      1. edituvw_flatten
    2. Click OK
    3. Wait for flattening
      1. edituvw_flattened
  5. At this point I’m guessing the real artists will make sure the UV’s unwrapped in a visually pleasing and correct manner.  I don’t relax the mapping at all, I just take it as is.
  6. You should see a nice flattened UV map.  Next go to your 3DS Max modifier stack and see that you have a ‘Unwrap UVW’ modifier.  Click on it and under Parameters->Map Channel select 2.
  7. Next we need to add some lighting.  For a very simple scene:
    1. Go to Create->Lights->StandardLights->SkyLight.  Create it wherever you like
    2. Go to Create->Lights->StandardLights->OmniLight.  Create it where you want the light to come from.
      1. Click on the light you just made and go to the Properties menu to the right.
      2. Turn Shadows ‘On’
      3. Under ‘Shadow Map Params’ I recommend changing the Bias to 0 otherwise your shadows will stand off from their geometry.
  8. Go To Rendering->Render Setup
  9. In the ‘Advanced Lighting’ tab select ‘Light Tracer’ from the drop down menu.  Default settings work but I would recommend changing Bounce to 1 or 2.  Feel free to play around a bit, these settings affect the end result.  Don’t go too crazy though or it will take forever and a year to render.
  10. Test your lighting by going to ‘Rendering->Render’  There should be nice soft shadows in your map.  If not, check your lights and make sure the Omni light is set to cast shadows.

Setting up OgreMax:

  1. Highlight all objects in the scene
  2. Go to OgreMax->Convert To OgreMax Materials.  This step converts all material and submaterials to the OgreMax material type.  Whereas normally you’d render the lightmap to something like the diffuse channel we need to modify things to allow for OgreMax to export the texture to Ogre properly
  3. *Optionally if you have a shared textures and are doing the per-object lightmap method you need to go to OgreMax->Create Master/Slave materials
  4. Go to OgreMax->Set Render To Texture Destinations and change Technique to 2.

Rendering to Texture:

  1. Gods finally.  Click on your merged object
  2. Go to ‘Rendering->Render To Texture…’ in the main 3DS Max window.
  3. Under ‘Objects To Bake->Mapping Coordinates’ choose ‘Use Existing Channel’ and set the channel to 2.
    1. rendertotexture1
    2. rendertotexture2
  4. Under ‘Output’ click ‘Add’ and add a Lightmap.   In ‘Target Map Slot’ choose ‘Technique 2′
  5. Under ‘Baked Material->Baked Material Settings’ click on ‘Output Into Source’
  6. Render

Done… sorta.  So this is where things get a bit hacky.  You can’t directly export the entire scene, or at least I couldn’t.  For some  reason Ogremax didn’t distigiush between all of the original meshes and the new mesh so it output them all to the scene file.  In other words we have our combined mesh AND the meshes we merged to make that mesh, thus creating duplicate geometry.  To avoid this problem manually select the things you’d like to export to Ogre and click OgreMax->Export Selected Items.  There might be an easier way to do this, I don’t know.

If you go to the export folder you should see your new .scene and .material files.  If you didn’t specify a Render To Texture output folder it is probably in MyDocuments->3DSMax->sceneassets.  Copy this and any original textures for your scene in to a single folder.

The last little hacky bit deals with the material files. You should see something like the one below:

material Road_Ar3_SG_OgreMax
{
	technique Map#58
	{
		pass Map#59
		{
			ambient 0 0 0 1
			specular 0 0 0 1 8
 
			texture_unit Map#60
			{
				texture_alias Map#60
				texture Road_Ar3.bmp
				filtering linear linear linear
			}
		}
 
	}
 
	technique Map#198
	{
		pass Map#199
		{
			ambient 0.698039 0.698039 0.698039 1
			diffuse 0.698039 0.698039 0.698039 1
			specular 0.898039 0.898039 0.898039 1 20
 
			texture_unit Map#291
			{
				texture_alias Map#291
				texture multiObjectsUnwrapLightingMap.tga
				tex_coord_set 1
				filtering linear linear linear
			}
		}
 
	}
 
}

In the first material->Technique we see the original texture is listed and in the second material->technique we see our scene lightmap texture.  Notice the tex_coord_set is 1 for the scene lightmap.  Each Ogre mesh can store multiple sets of UV’s (the ‘channels’ you create in 3DS Max.)  In my example there are 2 channels, 1 for the original texture sets and 1 for the lightmap.

I wrote a small bit of code(end of my post) to convert the above material to this material:

material Road_Ar3_SG_OgreMax
{
     technique
     {
          pass
          {
               ambient 1 1 1
               diffuse 1.0 1.0 1.0
               specular 1.0 1.0 1.0 9800.0
               emissive 0.0 0.0 0.0 1
               texture_unit
               {
                    texture Road_Ar3.bmp
                    tex_coord_set 0
                    colour_op modulate
               }
          }
          pass
          {
               scene_blend modulate
               texture_unit
               {
                    texture multiObjectsUnwrapLightingMap.tga
                    tex_coord_set 1
                    colour_op modulate
               }
          }
     }
}

Notice that we modified it to use scene blending. And we’re left with the final scene:

final

Lastly lets not forget my code. Keep in mind I wrote this in about 15 minutes to work exactly with what I’ve done above. It would probably be easier to use Ogre’s built in Material classes to parse the data and then modify as needed. You might also notice that I pull the image name from the material name.  If you follow OgreMax’s lightmapping tutorial you end up overwriting the original texture channel information.  This channel contains the original image name.  But OgreMax does export that name to the material name so I pulled it from there. (**This functionality isn’t needed with my tutorial, we make sure to write the values to a second texture alias.  Feel free to modify the code to simply read the original texture name.)

The code should load any material file but look closely at the output function.  The output structure is hardcode.  Yes yes, I know it isn’t pretty.

Code


Edit: UV Multi Unwrap has some error-catching flaws, namely it can’t handle deleted nodes or dummy objects. I’m posting my updated version of the script. Honestly I don’t know if my changes have any long term effects but in the near term I was able to successfully shade my new content. You can find my additions to the script by searching for “–jeremy”, you’ll see what I’ve done.

New multiObjectsUnwrapMacro If direct installation doesn’t work just copy and past my .mcr in to the current multiObjectsUnwrapMacro.mcr using the 3DS Max macro editor.

Categories: Uncategorized Tags: