Monday, 13 January 2014

Blogging Tools

Spontaneous Projects is a chronicle of all of my projects, a reference for me, and a way to prevent others from making the same mistakes. 

Code Blocks

This is the code block I use, it's stolen wholesale from somewhere else on the web, but I'm afraid I can't recall where. I'm still not fully happy with it, and I'll likely keep modifying it, but it works.

Open up your Blogger page, go to template, customise, Advanced > Add CSS

And add the following code block:
.code { background:#f5f8fa; background-repeat:no-repeat; border: solid #5C7B90; border-width: 1px 1px 1px 20px; color: green ; font: 13px 'Courier New', Courier, monospace; line-height: 16px; margin: 10px 0 10px 10px; max-height: 200px; min-height: 16px; overflow: auto; padding: 28px 10px 10px; width: 90%; } .code:hover { background-repeat:no-repeat;}
Apply the template to your blog and you can use it whenever you wish. I stole it wholesale from somewhere else on the web... can't recall where I'm afraid. You can vary the colours, and any of the other options as you wish.
To use it type your code in the compose window, switch to HTML and add <div class="code"> to the start of the block, and </div> to the end.

<div class="code">

#include
your code block here
# comments

</div>


Tables


Frame Only
Final Weight
v1.0
588g
1.37kg
v2.0
271g
1.04kg

<table 100="" border="1" bordercolor="#0033FF" cellpadding="3" cellspacing="0" px="" tbody="" width:=""><tbody>
<tr><td><div style="text-align: center;">
<br /></div>
</td><td><div style="text-align: center;">
Frame Only</div>
</td><td><div style="text-align: center;">
Final Weight</div>
</td></tr>
<tr><td><div style="text-align: center;">
v1.0</div>
</td><td><div style="text-align: center;">
588g</div>
</td><td><div style="text-align: center;">
1.37kg</div>
</td></tr>
<tr><td><div style="text-align: center;">
v2.0</div>
</td><td><div style="text-align: center;">
271g</div>
</td><td><div style="text-align: center;">
1.04kg<br />
<div>
<br />
</div>
</div>
</td></tr>
</tbody></table>


  • To add or remove rows: remove the entire code between <tr> and </tr> (start/stop TableRow)
  • To add or remove columns: remove cells, <td> to </td>
  • Borders only change when page is previewed
  • Cell padding is inside borders
  • Cell spacing is between cells
  • Tables in code are ugly, and Blogger doesn't keep your formatting, so it has to be redone each time



Other Tips and Tricks

  • Alt+Print Screen on a win 7 or 8 machine does a screen cap of just the active window, so you don't need to make the rest of your desktop presentable. 
  • Multiple monitors are a god-send, always.

Matlab has a GUI tool?

So, I just found out that Matlab has a GUI creation tool, so the plus/minus tool I made in post one could have been done in Matlab, with a GUI front end. This would have been a lot quicker, but probably a lot less fun, and I wouldn't have added yet another language to my repertoire.

Either way I figured I'd have a play with the GUIde, so I tacked it on to my TimedWebcam function. This is a slight improvement over the Webcam.m function, in that it is only active between specified times.

Anyway, the GUI:

Open up Matlab, and enter "guide" (GUI de)

Create a new GUI with unicontrols

Create a simple Figure, 2 variable text boxes, 2 fixed ones, and a button:


Create the figure

Set the names and captions as you want them, as well as the starting values.

It will autocreate the basic script to generate and run the GUI, all you need to do is populate it.
In this case, all it does is feed the Start time <StT> and the Final time <FiT> to the preexisting function TimedWebcam (StT,FtT) when the main button is pressed, and keep the two variables updated if the values are changed.

The script is very similar to normal Matlab code, but because it is a series (parallel?) of individual functions, you can't pass variables directly. To do so we set a guidata object called handles which passes our data. to set a variable at the text box in this form we use:

handles.StT=StT;
guidata(hObject,handles)

and to retrieve it at the button we use

StT=handles.StT;

Pretty simple once you figure it out, and there are tutorials all over the web.

Full code:



function varargout = Webcam(varargin)
% WEBCAM M-file for Webcam.fig
%      WEBCAM, by itself, creates a new WEBCAM or raises the existing
%      singleton*.
%
%      H = WEBCAM returns the handle to a new WEBCAM or the handle to
%      the existing singleton*.
%
%      WEBCAM('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in WEBCAM.M with the given input arguments.
%
%      WEBCAM('Property','Value',...) creates a new WEBCAM or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before Webcam_OpeningFcn gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to Webcam_OpeningFcn via varargin.
%
%      *See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
%      instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES

% Edit the above text to modify the response to help Webcam

% Last Modified by GUIDE v2.5 13-Jan-2014 08:07:39

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @Webcam_OpeningFcn, ...
                   'gui_OutputFcn',  @Webcam_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT


% --- Executes just before Webcam is made visible.
function Webcam_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   command line arguments to Webcam (see VARARGIN)

% Choose default command line output for Webcam
clc
handles.output = hObject;

% Update handles structure
guidata(hObject, handles);

% UIWAIT makes Webcam wait for user response (see UIRESUME)
% uiwait(handles.figure1);


% --- Outputs from this function are returned to the command line.
function varargout = Webcam_OutputFcn(hObject, eventdata, handles)
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
varargout{1} = handles.output;


% --- Executes on button press in pushbutton1.
function pushbutton1_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
clc
StT=handles.StT;
FiT=handles.FiT;
%fid=fopen(filename,'rt');
fprintf('Starting Webcam capture at %d:00, finishing at %d:00. \n Ctrl+C to break. \n \n ',StT,FiT)
TimedWebcam(StT,FiT);




function Commence_Callback(hObject, eventdata, handles)
% hObject    handle to Commence (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of Commence as text
%        str2double(get(hObject,'String')) returns contents of Commence as a double
StT = str2double(get(hObject,'String'));
handles.StT=StT;
guidata(hObject,handles)

% --- Executes during object creation, after setting all properties.
function Commence_CreateFcn(hObject, eventdata, handles)
% hObject    handle to Commence (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white'),set(hObject,'string','9');
end
StT = str2double(get(hObject,'String'));
handles.StT=StT;
guidata(hObject,handles)



function Finalise_Callback(hObject, eventdata, handles)
% hObject    handle to Finalise (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of Finalise as text
%        str2double(get(hObject,'String')) returns contents of Finalise as a double
FiT = str2double(get(hObject,'String'));
handles.FiT=FiT;
guidata(hObject,handles)

% --- Executes during object creation, after setting all properties.
function Finalise_CreateFcn(hObject, eventdata, handles)
% hObject    handle to Finalise (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white',set(hObject,'string','17'));
end
FiT = str2double(get(hObject,'String'));
handles.FiT=FiT;
guidata(hObject,handles)

Sunday, 12 January 2014

Not-so-spontaneous installing of OpenCV

Spontaneous Projects is a chronicle of all of my projects, a reference for me, and a way to prevent others from making the same mistakes. 

I think I've finally succeeded, it still needs some testing with other code, because I don't know how the integrated test programs function, but I think I managed it.

For the first section of this little saga check the older post here.

For the most part I followed these directions from murga-linux

Preparation


First, download and install Lucid Puppy (5.2.8 works)
Then, you need to download the devx file.

Then we need a few PET files, some of the ones in the linked post cause issues, with crashing xwin, or crashing the console somehow. On top of that they don't seem to be needed, it's possible that they are now rolled into the distro or the devx package.

DO NOT get new gtk+ files, they cause the xwin problem, and are not needed.

Download these from http://distro.ibiblio.org/puppylinux/pet_packages-4/
  • ffmpeg-20080731-i486.pet
  • ffmpeg_DEV-20080731-i486.pet
  • libjpeg-6b.pet
  • libpng-1.2.22-patched1-pup4.pet
  • libtiff-3.7.4.pet
  • fontconfig-2.6.0-prescott.pet
  • fontconfig_DEV-2.6.0-prescott.pet
  • x264-20080731-2245-i486.pet 
as well as

Now we add the devx sfs using SFS on-the-fly (Menu>Setup>Setup Puppy)

Back up your save file here, with wireless, a browser, the devx package and everything else needed for basic functionality.

Then install the PET's, just click run, or save and run them later. 

I reboot every now and then, because the xwin issues didn't manifest till the reboot, but given that I 
tracked them to xlib it shouldn't be an issue.

Installing


make the directory where you want OpenCV (</...OpenCV>)

#cd </...OpenCV>
#svn co http://opencvlibrary.svn.sourceforge.net/svnroot/opencvlibrary/trunk .

#cd </...OpenCV>trunk/opencv
#mkdir release
#cd release

#cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D BUILD_PYTHON_SUPPORT=ON ..

#make
#make install

#ldconfig -v
#export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
#cd </...OpenCV>/trunk/opencv
#export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig

These tests didn't run from terminal, I think they are actually in a different directory. You can find them manually though

#cd </...OpenCV>/opencv/trunk/release/bin
#./cxcoretest
#./cvtest -d </...OpenCV>/trunk/opencv/tests/cv/testdata/cv



I had no failures on the cxcore test, But the cv one had some, likely due to lack of inputs - it also had a segementation fault, so hopefully that isn't problematic.

Update: 13/1/14
I've compiled the samples, so it looks like it's all working as expected.
To run the samples, navigate to

</...OpenCV>/trunk/opencv/sample/c

and open a terminal. For LuPu you need to specify that you wish to use shell, so enter

sh build_all.sh

./edge
./motempl (if you have a webcam)
./ <any other program>
Use Esc to exit any of the samples

motempl in action, from what I can gather it identifies regions that have changed between frames

A little more movement in this one

And lots of movement as I move my hand and wave it about

Friday, 10 January 2014

Installing OpenCV (or trying to)

Spontaneous Projects is a chronicle of all of my projects, a reference for me, and a way to prevent others from making the same mistakes. 

I've spent the last few days trying to install openCV, an open source Computer Vision library.

It's not designed for Lucid Puppy, but there are posts about that indicate that it is possible. I've tried following the instructions for ubuntu on OpenCV's site, and got to 68% completion, but I was unable to find exact matches of some of the packages, and I think I may have forgotten to install dependecies on another - I thought it was an optional one, but maybe not.

I then tried the process shown at Murga-linux
As I was installing .pet files the computer siezed up a little, and seemed to stop installing them, on a reboot it appears that I have corrupted xwin. This isn't exactly surprising, given that I didn't remove the old packages, or make any effort to clean up.

So it looks like I'll be reinstalling LuPu and trying again using the Murga approach, but given that I was already planning on a fresh install soon it's not really an issue.

I was also able to copy my working directory from the SSD to a USB from the command line, so it appears that it's just xwin that is corrupt - I could probably try to fix it, but a reinstall will be easier.

Monday, 6 January 2014

Image Capture on linux

Spontaneous Projects is a chronicle of all of my projects, a reference for me, and a way to prevent others from making the same mistakes. 

For the first part of migrating to using the netbook as a computer vision device, I need to get an image from it.
I used a program called uvccapture as a basis, and modified it heavily, so that it runs in YUY mode all of the time, and has a lot less options, as I plan to use a modified version of this to capture for actual processing later.

The following was developed for a EeePC 701sd, running lucid puppy and compiled using g++ and a make file, the name is still the original, as I haven't fully got my head around how the makefiles work yet, so I kept it simple.
Lucid Puppy, (right) an older image showing both lack of centering and bad colours
(left) a recent pic, taken at the full res of the camera, in worse lighting, but with 1 second for the camera to adjust



#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <jpeglib.h>
#include <time.h>
#include <linux/videodev.h>

#include "v4l2uvc.h"

static const char version[] = VERSION;
int run = 1;

void
sigcatch (int sig)
{
  fprintf (stderr, "Exiting...\n");
  run = 0;
}

void
usage (void)
{
  fprintf (stderr, "uvccapture version %s\n", version);
  fprintf (stderr, "Usage is: uvccapture [options]\n");
  fprintf (stderr, "Options:\n");
  //fprintf (stderr, "-v\t\tVerbose\n");
  //fprintf (stderr, "-o<filename>\tOutput filename(default: snap.jpg)\n");
  //fprintf (stderr, "-d<device>\tV4L2 Device(default: /dev/video0)\n");
  //fprintf (stderr,
  //"-x<width>\tImage Width(must be supported by device)(>960 activates YUYV capture)\n");
  //fprintf (stderr,
  //"-y<height>\tImage Height(must be supported by device)(>720 activates YUYV capture)\n");
  //fprintf (stderr,
  //"-c<command>\tCommand to run after each image capture(executed as <command> <output_filename>)\n");
  //fprintf (stderr,
  //"-t<integer>\tTake continuous shots with <integer> seconds between them (0 for single shot)\n");
  //fprintf (stderr,
  //"-q<percentage>\tJPEG Quality Compression Level (activates YUYV capture)\n");
  //fprintf (stderr, "-r\t\tUse read instead of mmap for image capture\n");
  //fprintf (stderr,
  //"-w\t\tWait for capture command to finish before starting next capture\n");
  fprintf (stderr, "-m\t\tToggles capture mode to YUYV capture\n");
  //fprintf (stderr, "Camera Settings:\n");
  //fprintf (stderr, "-B<integer>\tBrightness\n");
  //fprintf (stderr, "-C<integer>\tContrast\n");
  //fprintf (stderr, "-S<integer>\tSaturation\n");
  //fprintf (stderr, "-G<integer>\tGain\n");
  exit (8);
}

int
spawn (char *argv[], int wait, int verbose)
{
  pid_t pid;
  int rv;

  switch (pid = fork ()) {
  case -1:
    return -1;
  case 0:
    // CHILD
    execvp (argv[0], argv);
    fprintf (stderr, "Error executing command '%s'\n", argv[0]);
    exit (1);
  default:
    // PARENT
    if (wait == 1)  
      waitpid (pid, &rv, 0);
 
    else {
      // Clean zombies
      waitpid (-1, &rv, WNOHANG);
      rv = 0;
    }
    break;
  }

  return rv;
}

int
compress_yuyv_to_jpeg (struct vdIn *vd, FILE * file, int quality)
{
  struct jpeg_compress_struct cinfo;
  struct jpeg_error_mgr jerr;
  JSAMPROW row_pointer[1];
  unsigned char *line_buffer, *yuyv;
  int z;
  sleep(1);
  line_buffer = calloc (vd->width * 3, 1);
  yuyv = vd->framebuffer;

  cinfo.err = jpeg_std_error (&jerr);
  jpeg_create_compress (&cinfo);
  jpeg_stdio_dest (&cinfo, file);

  cinfo.image_width = vd->width;
  cinfo.image_height = vd->height;
  cinfo.input_components = 3;
  cinfo.in_color_space = JCS_RGB;

  jpeg_set_defaults (&cinfo);
  jpeg_set_quality (&cinfo, quality, TRUE);

  jpeg_start_compress (&cinfo, TRUE);

  z = 0;
  while (cinfo.next_scanline < cinfo.image_height) {
    int x;
    unsigned char *ptr = line_buffer;

    for (x = 0; x < vd->width; x++) {
      int r, g, b;
      int y, u, v;

      if (!z)
y = yuyv[0] << 8;
      else
y = yuyv[2] << 8;
      u = yuyv[1] - 128;
      v = yuyv[3] - 128;

      r = (y + (359 * v)) >> 8;
      g = (y - (88 * u) - (183 * v)) >> 8;
      b = (y + (454 * u)) >> 8;

      *(ptr++) = (r > 255) ? 255 : ((r < 0) ? 0 : r);
      *(ptr++) = (g > 255) ? 255 : ((g < 0) ? 0 : g);
      *(ptr++) = (b > 255) ? 255 : ((b < 0) ? 0 : b);

      if (z++) {
z = 0;
yuyv += 4;
      }
    }

    row_pointer[0] = line_buffer;
    jpeg_write_scanlines (&cinfo, row_pointer, 1);
  }

  jpeg_finish_compress (&cinfo);
  jpeg_destroy_compress (&cinfo);

  free (line_buffer);

  return (0);
}

int
main (int argc, char *argv[])
{
  char *videodevice = "/dev/video0";
  char *outputfile = "new.jpg";

  //int format = V4L2_PIX_FMT_MJPEG; // OR
  int format = V4L2_PIX_FMT_YUYV;

  int grabmethod = 1;
  int width = 640;
  int height = 480;
  int brightness = 0, contrast = 0, saturation = 0;
  int delay = 0; // increased, may sort out the wrap issues, results in other issues, but fixes colours
  int quality = 95;
  time_t ref_time;
  struct vdIn *videoIn;
  FILE *file;

  (void) signal (SIGINT, sigcatch);
  (void) signal (SIGQUIT, sigcatch);
  (void) signal (SIGKILL, sigcatch);
  (void) signal (SIGTERM, sigcatch);
  (void) signal (SIGABRT, sigcatch);
  (void) signal (SIGTRAP, sigcatch);



  //Options Parsing (FIXME)
  while ((argc > 1) && (argv[1][0] == '-')) {
    switch (argv[1][1]) {

    case 'm':
       format = V4L2_PIX_FMT_YUYV;
      break;

    default: // this an unknown was entered case, nb -h is that
      fprintf (stderr, "Unknown option %s \n", argv[1]);
      format = V4L2_PIX_FMT_YUYV; // added here
      usage ();
    }
    ++argv;
    --argc;
  }


  videoIn = (struct vdIn *) calloc (1, sizeof (struct vdIn));
  if (init_videoIn
      (videoIn, (char *) videodevice, width, height, format, grabmethod) < 0)
    exit (1);

  //Reset all camera controls

  v4l2ResetControl (videoIn, V4L2_CID_BRIGHTNESS);
  v4l2ResetControl (videoIn, V4L2_CID_CONTRAST);
  v4l2ResetControl (videoIn, V4L2_CID_SATURATION);
  //v4l2ResetControl (videoIn, V4L2_CID_GAIN);

  //Setup Camera Parameters
  if (brightness != 0)
    v4l2SetControl (videoIn, V4L2_CID_BRIGHTNESS, brightness);

  if (contrast != 0)
      v4l2SetControl (videoIn, V4L2_CID_CONTRAST, contrast);

  if (saturation != 0)
     v4l2SetControl (videoIn, V4L2_CID_SATURATION, saturation);
 
  //if (gain != 0)    // It appears that gain does not exist, in this format, on this camera... who knows?
    //v4l2SetControl (videoIn, V4L2_CID_GAIN, gain);
 
 
  ref_time = time (NULL);

  while (run) {
 
    if (uvcGrab (videoIn) < 0) {
      fprintf (stderr, "Error grabbing\n");
      close_v4l2 (videoIn);
      free (videoIn);
      exit (1);
    }

    if ((difftime (time (NULL), ref_time) > delay) || delay == 0) {

      file = fopen (outputfile, "wb");
      if (file != NULL) {
switch (videoIn->formatIn) {
case V4L2_PIX_FMT_YUYV:
 compress_yuyv_to_jpeg (videoIn, file, quality);
 break;
default:
 fwrite (videoIn->tmpbuffer, videoIn->buf.bytesused + DHT_SIZE, 1,
 file);
 break;
}
fclose (file);
videoIn->getPict = 0;
      }
   
      ref_time = time (NULL);
    }
    if (delay == 0)
      break;
  }
  close_v4l2 (videoIn);
  free (videoIn);

  return 0;
}


Some Notes:

  • uvccapture uses some strange settings when initialising the camera, if there is not a delay to allow the camera to choose it's own settings it can be out of alignment, invert the colours, or be over/under saturated.
  • The gain function doesn't seem to exist for this setup, and throws an error 22 bug, once I commented out those lines it fixed itself. I'm not sure if it's hardware, software, or something else
  • There is likely still an amount of this that could be cut down, but until I know how I need the images to use them it will stay as it is. 


Early images, note the wrapping issue, and red appears blue

Recent image, with these issues corrected