Resizing Oracle’s Pre-Built Development Virtual Machines

Expand the size of Oracle’s Pre-Built Development VM’s (virtual appliances) to accommodate software package updates and additional software installations.

Introduction

In my last post, Using Oracle’s Pre-Built Enterprise Java VM for Development Testing, I discussed issues with the small footprint of the VM. Oracle’s Pre-Built Enterprise Java Development VM, aka virtual appliance, is comprised of (2) 8 GB Virtual Machine Disks (VMDK). The small size of the VM made it impossible to update the system software, or install new applications. After much trial and error, and a few late nights reading posts by others who had run into this problem, I found a fairly easy series of steps to increase the size of the VM. In the following example, I’ll demonstrate how to resize the VM’s virtual disks to 15 GB each; you can resize the disks to whatever size you need.

Terminology

Before we start, a few quick terms. It’s not critical to have a complete understanding of Linux’s Logical Volume Manager (LVM). However, without some basic knowledge of how Linux manages virtual disks and physical storage, the following process might seem a bit confusing. I pulled the definitions directly from Wikipedia and LVM How-To.

  • Logical Volume Manager (LVM) – LVM is a logical volume manager for the Linux kernel; it manages disk drivers and similar mass-storage devices.
  • Volume Group (VG) – Highest level abstraction within the LVM. Gathers Logical Volumes (LV) and Physical Volumes (PV) into one administrative unit.
  • Physical Volume (PV) – Typically a hard disk, or any device that ‘looks’ like a hard disk (eg. a software raid device).
  • Logical Volume (LV) – Equivalent of disk partition in a non-LVM system. Visible as a standard block device; as such the LV can contain a file system (eg. /home).
  • Logical Extents (LE) – Each LV is split into chunks of data, known as logical extents. The extent size is the same for all logical volumes in the volume group. The system pools LEs into a VG. The pooled LEs can then be concatenated together into virtual disk partitions (LV).
  • Virtual Machine Disk (VMDK) – Container for virtual hard disk drives used in virtual machines. Developed by VMware for its virtual appliance products, but is now an open format.
  • Virtual Disk Image (VDI) – VirtualBox-specific container format for storing files on the host operating system.

Ten Simple Steps

After having downloaded, assembled, and imported the original virtual appliance into VirtualBox Manager on my Windows computer, I followed the these simple steps to enlarge the size of the VM’s (2) 8 GB VMDK files:

  1. Locate the VM’s virtual disk images;
  2. Clone VMDK files to VDI files;
  3. Resize VDI files;
  4. Replace VM’s original VMDK files;
  5. Boot VM using GParted Live;
  6. Resize VDI partitions;
  7. Resize Logical Volume (LV);
  8. Resize file system;
  9. Restart the VM;
  10. Delete the original VMDK files.
Original VM in VirtualBox Manager Before Resizing

Original VM in VirtualBox Manager Before Resizing

Original View of VM Before Resizing and Software Updates

Original View of VM Before Resizing and Software Updates

1. Locate the VM’s virtual disk images

  • From the Windows command line, run the following command to find information about virtual disk images currently in use by VirtualBox.
  • Locate the (2) VMDK images associated with the VM you are going to resize.
cd C:\Program Files\Oracle\VirtualBox
VBoxManage list hdds
Two Virtual Disk Images in use by VM

Two Virtual Disk Images in use by VM

2. Clone the (2) VMDK files to VDI files (substitute your own file paths and VMDK file names)

VBoxManage clonehd "C:\Users\your_username\VirtualBox VMs\VDD_WLS_labs_2012\VDD_WLS_labs_2012-disk1.vmdk" "C:\Users\your_username\VirtualBox VMs\VDD_WLS_labs_2012\VDD_WLS_labs_2012-disk1_ext.vdi" --format vdi
VBoxManage clonehd "C:\Users\your_username\VirtualBox VMs\VDD_WLS_labs_2012\VDD_WLS_labs_2012-disk2.vmdk" "C:\Users\your_username\VirtualBox VMs\VDD_WLS_labs_2012\VDD_WLS_labs_2012-disk2_ext.vdi" --format vdi

3. Resize the (2) VDI files

To calculate the new size, multiple the number of gigabytes you want to end up with by 1,024 (ie. 15 x 1,024 = 15,360)

VBoxManage modifyhd "C:\Users\your_username\VirtualBox VMs\VDD_WLS_labs_2012\VDD_WLS_labs_2012-disk1_ext.vdi" --resize 15360
VBoxManage modifyhd "C:\Users\your_username\VirtualBox VMs\VDD_WLS_labs_2012\VDD_WLS_labs_2012-disk2_ext.vdi" --resize 15360

4. Replace the VM’s original VMDK files with the VDI files

  • Using VirtualBox Manger -> Settings -> Storage, replace the (2) original VMDK files with the new VDI files.
  • Keep the Attributes -> Hard Disk set to the same SATA Port 0 and SATA Port 1 of the original VMDK files.
VirtualBox Manager Showing VM with Larger Disks and GParted Live ISO

VirtualBox Manager Showing VM with Larger Disks and GParted Live ISO

5. Boot VM using the GParted Live ISO image

  • Download GParted Live ISO image to the host system (Windows).
  • Mount the GParted ISO (Devices -> CD/DVD Devices -> Chose a virtual CD/DVD disk file…).
  • Start the VM, hit f12 as VM boots up, and select CD/DVD (option c).
  • Answer a few questions for GParted to boot up properly.

Booting into GParted Live ISO 0

Booting into GParted Live ISO 1

Booting into GParted Live ISO 2

Booting into GParted Live ISO 3

Booting into GParted Live ISO 4

6. Using GParted, resize the (2) VDI partitions

  • Expand the ‘/dev/sda2′ and ‘/dev/sdb1′ partitions to use all unallocated space (in gray below).

Expanding Partition of New VM Disk 07

Expanding Partition of New VM Disk 06

Expanding Partition of New VM Disk 05

7. Resize Logical Volume (LV)

  • Using the Terminal, resize the Logical Volume to the new size of the VDI (‘/dev/sda’).
lvresize -L +7GB /dev/VolGroup00/LogVol00

Resizing the Logical Volume

8. Resize file system

  • Using the Terminal, resize the file system to match Logical Volume size.
resize2fs -p /dev/mapper/VolGroup00-LogVol00

9. Restart the VM

  • Restart the VM, hit f12 as it’s booting up, and select ’1) Hard disk’ as the boot device.
  • Open the Terminal and enter ‘df -hT’ to confirm your results.
  • You can now safely install YUM Server configuration to update software packages, and install new applications.
Final View of VM After Resizing and Software Updates

Final View of VM After Resizing and Software Updates

10. Delete the original VMDK files

  • Once you sure everything worked, don’t forget to delete the original VMDK files. They are taking up 16 GB of disk space.

Links

Here are links to the two posts where I found most of the above information:

  1. How to resize a VirtualBox vmdk file
  2. LVM Resizing Guide – Grow File System

, , , , , , , , ,

1 Comment

Using Oracle’s Pre-Built Enterprise Java VM for Development Testing

Install and configure Oracle’s Pre-Built Enterprise Java Development VM, with Oracle Linux 5, to create quick, full-featured development test environments. 

Login Splash Screen for VM

Virtual Machines for Software Developers

As software engineers, we spend a great deal of time configuring our development machines to simulate test and production environments in which our code will eventually run. With the Microsoft/.NET technology stack, that most often means installing and configuring .NET, IIS, and SQL Server. With the Oracle/Java technology stack – Java, WebLogic or GlassFish Application Server, and Oracle 11g.

Within the last few years, the growth of virtual machines (VMs) within IT/IS organizations has exploded. According to Wikipedia, a virtual machine (VM), is ‘a software implementation of a machine (i.e. a computer) that executes programs like a physical machine.’ Rapid and inexpensive virtualization of business infrastructure using VMs has led to the exponential growth of private and public cloud platforms.

Instead of attempting to configure development machines to simulate the test and production environments, which are simultaneously running development applications and often personal programs, software engineers can leverage VMs in the same way as IT/IS organizations. Free, open-source virtualization software products from Oracle and VMware offer developers the ability to easily ‘spin-up’ fresh environments to compile, deploy, and test code. Code is tested in a pristine environment, closely configured to match production, without the overhead and baggage of  day-to-day development. When testing is complete, the VM is simply deleted and a new copy re-deployed for the next project.

Oracle Pre-Built Virtual Appliances

I’ve worked with a number of virtualization products, based on various Windows and Linux operating systems. Not matter the product or OS, the VM still needs to be set up just like any other new computer system, with software and configuration. However, recently I began using Oracle’s pre-built developer VMs. Oracle offers a number of pre-built VMs for various purposes, including database development, enterprise Java development, business intelligence, application hosting, SOA development, and even PHP development. The VMs, called virtual appliances,  are Open Virtualization Format Archive files, built to work with Oracle VM VirtualBox. Simply import the appliance into VirtualBox and start it up.

Oracle has provided ready-made VMs that would take even the most experienced team of IT professionals days to download, install, configure, and integrate. All the configuration details, user accounts information, instructions for use, and even pre-loaded tutorials, are provided. Oracle notes on their site that these VMs are not intended for use in production. However, the VMs are more than robust enough to use as a development test environment.

Because of its similarity to my production environment, I the installed the Enterprise Java Development VM on a Windows 7 Enterprise-based development computer. The Oracle Linux 5 OS-based VM has almost everything that comprises basic enterprise test and production environment based on the Oracle/Java technology stack. The VM includes an application server, source control server, build automation server, Java SDK, two popular IDE’s, and related components. The VM includes Java JDK 1.6+, WebLogic Server, Coherence, TopLink, Subversion, Hudson, Maven, NetBeans, Enterprise Pack for Eclipse, and so forth.

Aside from a database server, the environment has everything most developers might need to develop, build, store, and host their code. If you need a database, as most of us do, you can install it into the VM, or better yet, implement the Database App Development VM, in parallel. The Database VM contains Oracle’s 11g Release 2 enterprise-level relational database, along with several related database development and management tools. Using a persistence layer (data access layer), built with the included EclipseLink, you can connect the Enterprise appliance to the database appliance.

View of Oracle WebLogic 12c Running within VM

View of Oracle WebLogic 12c Running within VM

Set-Up Process

I followed the following steps to setup my VM:

  1. Update (or download and install) Oracle VM VirtualBox to the latest release.
  2. Download (6) Open Virtualization Format Archive (OVF/.ova) files.
  3. Download script to combine the .ova files.
  4. Execute script to assemble (6) .ova files into single. ova file.
  5. Import the appliance (combined .ova file) into VirtualBox.
  6. Optional: Clone and resize the appliance’s (2) virtual machines disks (see note below).
  7. Optional: Add the Yum Server configuration to the VM to enable normal software updates (see instructions below).
  8. Change any necessary settings within VM: date/time, timezone, etc.
  9. Install and/or update system software and development applications within VM: Java 1.7, etc.
View of Final OVF File Ready for Import

View of Combined OVF File Ready for Import into VirtualBox

View of Oracle VM VirtualBox Manager for Windows

View of Appliance within Oracle VM VirtualBox Manager for Windows

View of Pre-Built VM Running on Oracle VM VirtualBox

View of Pre-Built VM Running on Oracle VM VirtualBox Prior to Software Updates

Issue with Small Footprint of VM

The small size of the of pre-built VM is major issue I ran into almost immediately. Note in the screen grab above of VirtualBox, the Oracle VM only has (2) 8 GB virtual machine disks (.vmdk). Although Oracle designed the VMs to have a small footprint, it was so small that I quickly filled  up its primary partition. At that point, the VM was too full to apply the even the normal system updates. I switched the cache location for yum to a different partition, but then ran out of space again when yum tried to apply the updates it had downloaded to the primary partition.

Lack of disk space was a complete show-stopper for me until I researched a fix. Unfortunately, VirtualBox’s ‘VBoxManage modifyhd –resize’ command is not yet compatible with the virtual machine disk (.vmdk) format. After much trial and error, and a few late nights reading posts by others who had run into this problem, I found a fairly easy series of steps to enlarge the size of the VM. It doesn’t require you to be a complete ‘Linux Geek’, and only takes about 30 minutes of copying and restarting the VM a few times. I will included the instructions in this separate, upcoming post.

Expanded VM Disks in New Copy of Appliance

Expanded VM Disks in New Copy of Appliance

Issue with Package Updater

While solving the VM’s disk space issue, I also discoverer the VM’s Enterprise Linux System was setup with something called the Unbreakable Linux Network (ULN) Update Agent. From what I understood, without a service agreement with Oracle, I could not update the VM’s software using the standard Package Updater. However, a few quick commands I found on the Yum Server site, overcame that limitation and allowed me to update the VM’s software. Just follow the simple instructions here, for Oracle Linux 5. There are several hundred updates that will be applied, including an upgrade of Oracle Linux from 5.5 to 5.9.

Software Updates Now Working Using Yum Server

Software Updates Now Working Using Yum Server Repo

Issue with Java Updates

Along with the software updates, I ran into an issue installing the latest version of Java. I attempted to install the standard Oracle package that contained the latest Java JDK, JRE, and NetBeans for Linux. Upon starting the install script, I immediately received a ‘SELinux AVC denial’ message. This security measure halted my installation with the following error: ‘The java application attempted to load /labs/java/jre1.7.0_21/lib/i386/client/libjvm.so which requires text relocation. This is a potential security problem.

To get around the SELinux AVC denial issue, I installed the JRE, JDK, and NetBeans separately. Although this took longer and required a number of steps, it allowed me to get around the security and install the latest version of Java.

Note I later discovered that I could have simply changed the SELinux Security Level to ‘Permissive’ in the SELinux Security and Firewall, part of the Administrative Preferences. This would have allowed the original Oracle package containing the JDK, JRE, and NetBeans, to run.

Changing the SELinux Security Level to Allow Installation of Java and NetBeans

Changing the SELinux Security Level to Allow Installation of Java and NetBeans

Links

, , , , , , , , , , , , , ,

Leave a Comment

Using soapUI to Test RESTful Web Services

Introduction

There are many excellent tools available to test RESTful web services. Applications like Fiddler, cURL, Firefox with Firebug, and Google Chrome’s Advanced REST Client and REST Console are commonly used by developers and test engineers. Another powerful tool, used by many enterprise software development organizations, is soapUI by SmatBear Software.

SmartBear offers several versions, from the free open-source edition (shown here), to the full-featured soapUI Pro. Although, soapUI Pro has many useful advanced features, the free edition is fine to start with. Here is a product comparison of the various editions available from SmartBear.

SmartBear’s soapUI is available for Windows, Mac OS, and Linux (shown here). The application supports a wide range of technologies, including SOAP, WSDL, REST, HTTP, HTTPS, AMF, JDBC, JMS, WS-I Integeration, WS-Security, WS-Addressing, WS-Reliable Messaging, according to the SmartBear web site. It is easy to download and install.

SmartBear soapUI 4.5.1 for Linux

Testing RESTful Web Services with soapUI

In my last post, we used JDBC to map JPA entity classes to tables and views within a MySQL database. We then built RESTful web services, EJB classes, which communicated with MySQL through the entities. The RESTful web services, part of a Java Web Application, were deployed to GlassFish.

Architectural Diagram of Previous Post

Using that post’s RESTful web services, here is a quick example of how easy it is to use the free, open-source edition of soapUI to test those services. Start by locating the address of the RESTful service’s WADL. The WADL address is displayed in the upper left corner of the NetBeans’ browser-based test page, shown in the earlier post.

Displaying the RESTful Web Services WADL

Displaying the RESTful Web Services WADL

Next, create a new soapUI project. Give the project the WADL address and a project name.

Creating a New soapUI Project

Creating a New soapUI Project

Using the WADL, soapUI will create sample HTTP Request for each service resource’s methods (left-side of screen). Populating the sample request with any required input parameters, you make an HTTP Request to the service’s method.

In this first example, I call the Actor resource’s ‘findAll’ method using an HTTP GET method. The call to ‘http://localhost:8080/MySQLDemoService/webresources/com.mysql.entities.actor’  results in an HTTP Response with the list of Actor objects, mapped (serialized) to JSON  (right-side of screen).

Results of Querying the Actor's findAll Method URI

Results of Querying the Actor’s findAll Method

In this second example, I call the Film resource’s ‘Id’ method, to locate a single Film object, using the HTTP GET method. The call to ‘http://localhost:8080/MySQLDemoService/webresources/com.mysql.entities.film/719′  results in an HTTP Response with the a single Film object, identified by Id 719. This time the object is marshalled to XML, instead of JSON.

Querying the Film's Id Method with Input Parameter

Querying the Film’s Id Method with Input Parameter

, , , , , ,

Leave a Comment

Java RESTful Web Services Using MySQL Server, EclipseLink, and Jersey

Demonstrates the development of Java RESTful Web Services using MySQL Server, EclipseLink (JPA) and Jersey (JAX-RS). Built using NetBeans and hosted on GlassFish.
 
MySQL Diagram

Introduction

When implementing a Relational Database Management System (RDBMS), many enterprise software developers tend to favor Oracle 11g or Microsoft SQL Server relational databases, depending on their technology stack. However, there are several excellent alternative relational databases, including MySQL. In fact, MySQL is the world’s most popular open source database software, according to Oracle.

MySQL is available on over 20 platforms and operating systems including Linux, Unix, Mac and Windows, according to the MySQL website. Like Oracle and Microsoft’s flagship RDBMS, MySQL Server comes in at least four flavors, ranging from the free Community Edition, demonstrated here, to a full-featured, enterprise-level Cluster Carrier Grade Edition. Support for MySQL, like Oracle and Microsoft, extends beyond just technical support. MySQL provides JDBC, ODBC, .NET drivers for Java and .NET development, as well as other languages. MySQL is supported by many popular IDE’s, including MySQL’s own RDBMS IDE, MySQL Workbench. Lastly, like Oracle and Microsoft, MySQL provides extensive documentation, tutorials, and even sample databases, built using recommended architectural patterns.

In this post, we will use JDBC to map JPA entity classes to tables and views within a MySQL database. We will then build RESTful web services, EJB classes, which communicate with MySQL through the entities. We will separate the JPA entities into a Java Class Library. The class library will be referenced by the RESTful web services. The RESTful web services, part of a Java Web Application, will be deployed to GlassFish, where they are accessed with HTTP methods and tested.

Installation and Configuration

If you’ve worked with Microsoft SQL Server or particularly Oracle 11g, you’ll have a minimal learning curve with MySQL. Basic installation, configuration, and integration within your Java applications is like Oracle and Microsoft. Start by downloading and installing the latest versions of MySQL Server, MySQL Workbench, MySQL JDBC Connector/J Driver, and MySQL Sakila sample database. If on Linux, you could use the command line, or a native application management application, like Synaptic Package Manager, to perform most of the installations. To get the latest software and installation and configuration recommendations, I prefer to download and install them myself from the MySQL web site. All links are included at the end of this post.

For reference when following this post, I have installed MySQL Server 5.5.x on 64-bit Ubuntu 12.10 LTS, running within a Windows version of Oracle VM VirtualBox. I will be using the latest Linux version of NetBeans IDE 7.3 to develop the demonstration project. I will host the project on Oracle’s GlassFish Open Source Application Server 3.1.2.2, running on Ubuntu. Lastly, I will be referring to the latest JDK 1.7, in NetBeans, for the project.

MySQL Demo User Account

Once MySQL is installed and running, I suggest adding a new MySQL demo user account, to the Sakila database for this demonstration, using MySQL Workbench. For security, you should limit the user account to just those permissions necessary for this demonstration, as detailed in the following screen-grabs. You can also add the user from the command line, if you are familiar with administering MySQL in that way.

MySQL Workbench IDE

MySQL Workbench IDE

Configuring Demo User Login

Configuring Demo User Login

Configuring Demo User Administrative Roles

Configuring Demo User Administrative Roles

Configuring Demo User Account Limits

Configuring Demo User Account Limits

Configuring Demo User Schema Privileges

Configuring Demo User Schema Privileges

New MySQL Database Connection

To begin development in NetBeans, first create a new JDBC database connection to the MySQL Sakila database. In the Services tab, right-click on the Databases item and select New Connection… Use the new demo user account for the connection.

Note in the first screen-grab below, that instead of using the default NetBeans JDBC MySQL Connector/J driver version, I have downloaded and replaced it with the most current version, 5.1.24. This is not necessary, but I like to use the latest drivers to avoid problems.

New Connection Wizard - MySQL Driver

Locating the Driver in the New Connection Wizard

Make sure to test your connection before finishing, using the ‘Test’ button. It’s frustrating to track down database connection issues once you start coding and testing.

New Connection Wizard - Customize Connection

Customize the Connection in the New Connection Wizard

New Connection Wizard - Database Schema

Sakila Database Doesn’t Contain Additional Schema

Choosing a Name for the Connection

Choosing a Name for the Connection

New Database Connection for demoUser

New Database Connection for MySQL Sakila Database

New Java Class Library

Similar to an earlier post, create new Java Class Library project in NetBeans. Select New Project -> Java -> Java Class Library. This library will eventually contain the JPA entity classes, mapped to tables and views in the MySQL Sakila database. Following standard n-tier design principles, I prefer separate the data access layer (DAL) from the service layer. You can then reuse the data access layer for other types of data-consumers, such as SOAP-based services.

Create New Java Class Library Project

Create New Java Class Library Project

Naming New Java Class Library

Naming New Java Class Library

Entity Classes from Database

Next, we will add entity classes to our project, mapped to several of the MySQL Sakila database’s tables and views. Right-click on the project and select New -> Entity Classes from Database… In the next window, choose the database connection we made before. NetBeans will then load all the available tables and views from the Sakila database. Next, select ‘actor_info(view)’, ‘film_actor’, and ‘film_list(view)’. Three related tables will also be added automatically by NetBeans. Not the warning at the bottom of the window about the need to specify Entity IDs. We will address this next.

Choosing Database Tables and Views

Choosing Database Tables and Views

Entity Class Options

Entity Class Options

Entity Mapping Options

Entity Mapping Options

When selecting ‘Entity Classes from Database…’, NetBeans adds the ‘EclipseLink (JPA 2.0)’ global library to the project. This library contains three jars, including EclipseLink 2.3.x, Java Persistence API (JPA) 2.0.x, and state model API for JPQL queries. There is a newer EclipseLink 2.4.x library available from their web site.  The 2.4.x version has many new features. You can download and replace NetBeans’ EclipseLink (JPA 2.0) library by creating a new EclipseLink 2.4.x library, if you want to give its new features, like JPA-RS, a try. It is not necessary for this demonstration, however.

New Java Class Project with Entities

Java Class Project with JPA Entity Classes

Adding Entity IDs to Views

To eliminate warnings displayed when we built the entities, Entity ID’s must be designated for the two database views we selected, ‘actor_info(view)’ and ‘film_list(view)’. Database views (virtual tables), do not have a primary key defined, which NetBeans requires for the entity classes. NetBeans will guide you through adding the ID, if you click on the error icon shown below.

Adding Id to ActorInfo Entity

Adding and Entity ID to ActorInfo Entity

Id Added to Entity Class

Entity ID Added to Entity Class

New Java Web Application

Next, we will create the RESTful Web Services. Each service will be mapped to one of the corresponding JPA entity we just created in the Java class library project. Select New Project -> Java Web -> Web Application.

New Web Application Project

New Web Application Project

Naming New Web Application

Naming New Web Application

Configuring Server and Settings

Configuring Server and Settings

Configuring Frameworks

Configuring Frameworks

New Java Web Application Project

New Java Web Application Project

RESTful Web Services from Entity Classes

Before we will build the RESTful web services, we need to add a reference to the previous Java class library project, containing the JPA entity classes. In the Java web application’s properties dialog window, under Categories -> Libraries -> Compile, add a link to the Java class library project’s .jar file.

Adding MySQL Entity Class Library

Adding MySQL Entity Class Library

Next, right-click on the project and select New -> RESTful Web Services from Entity Classes…

Adding RESTful Web Service from Entities

Adding RESTful Web Service from Entity Classes

In the preceding dialogue window, add all the ‘Available Entity Classes’ to the ‘Selected Entity Classes’ column.

Choosing Entity Classes

Choosing Entity Classes

Chosen Entity Classes

Chosen Entity Classes

After clicking next, you will prompted to configure the Persistence Unit and the Persistence Unit’s Data Source. Please refer to my earlier post for more information on the Persistence Unit. This data source will also be used by GlassFish, once the project is deployed, to connect to the Sakila MySQL database. The Persistence Unit will use the JNDI name to reference the data source.

Creating Data Source for Persistence Unit

Creating Data Source for Persistence Unit

Creating Data Source and JNDI Name

Creating Data Source and JNDI Name

Creating Persistence Unit

Creating Persistence Unit

Generating Classes Using Jersey Options

Generating Classes Using Jersey Options

New Java Web Application with RESTful Web Services

Java Web Application with RESTful Web Services

As part of constructing the RESTful Web Services, notice NetBeans has added several Jersey (JAX-RS) libraries to the project. These libraries also reference Jackson (JSON Processor), Jettison (JSON StAX), MOXy (JAXB), and Grizzly (NIO) APIs.

Libraries Loaded by NetBeans to Java Web Application

Libraries Loaded by NetBeans to Java Web Application

Creating RESTful Web Services Test

Finally, we will test the RESTful Web Services, and indirectly the underlying entity classes mapped to the MySQL Sakila database. NetBeans makes this easy. To begin, right-click on the ‘RESTful Web Services’ folder in the Java web application project and select ‘Test RESTful Web Services’. NetBeans will automatically generate all the necessary files and links to test each of the RESTful web services’ operations.

As part of creating the tests, NetBeans will deploy the web application to GlassFish. When configuring the tests in the ‘Configure REST Test Client’ dialog window, make sure to use the second option, ‘Web Test Client in Project’. The first option only works with Microsoft’s Internet Explorer, an odd choice for a Java-based application running on Linux.

Configuring the REST Test Client

Configuring the REST Test Client

Highlighted below in red are the components NetBeans will install on the GlassFish application server. They include the RESTful web services application, a .war file. Each of the RESTful web service are Stateless Session Beans, installed as part of the application. In deployment also includes a JDBC Resource and a JDBC Connection Pool, which connects the application to the MySQL Sakila database. The Resource is automatically associated with the Connection Pool.

RESTful Web Services Deployed to GlassFish Server

RESTful Web Services Deployed to GlassFish Server

After creating the necessary files and deploying the application, NetBeans will open a web browser. allowing you can test the services. Each of the RESTful web services is available to test by clicking on the links in the left-hand navigation menu. NetBeans has generated a few default operations, including ‘{id}’, ‘{from/to}’, and ‘count’, each mapped to separate methods in the service classes. Also notice you can choose to display the results of the service calls in multiple formats, including XML, JSON, and plain text.

Testing RESTful Web Services from NetBeans

Testing RESTful Web Services from NetBeans Using Chrome

We can also test the RESTful Web Services by calling the service URLs, directly. Below, is the results of a my call to the Actor service’s URL, from a separate Windows client machine.

Calling the RESTful Web Services Directly

Calling the RESTful Web Services Directly

You can also use applications like Fiddler, cURL, Firefox with Firebug, and Google Chrome’s Advanced REST Client and REST Console to test the services. Below, I used Fiddler to call the Actor service, again. Note the response contains a JSON payload, not XML. With Jersey, you can request and receive JSON from the services without additional programming.

Fiddler2 Request Example

Fiddler2 Request Example

Conclusion

Using these services, you can build any number of server-side and client-side data-driven applications. The service layer is platform agnostic, accessible from any web-browser, mobile device, or native desktop application, on Windows, Linux, and Apple.

Links

MySQL Server: http://www.mysql.com/downloads/mysql

MySQL Connector/J JDBC driver for MySQL: http://dev.mysql.com/downloads/connector/j

MySQL Workbench: http://www.mysql.com/downloads/workbench

MySQL Sakila Sample Database: http://dev.mysql.com/doc/sakila/en/sakila-installation.html

NetBeans IDE: http://www.netbeans.org

EclipseLink: http://projects.eclipse.org/projects/rt.eclipselink

, , , , , , , , , , , , , ,

1 Comment

Instant Oracle Database and PowerShell How-to Book

Recently, I finished reading Geoffrey Hudik‘s Instant Oracle Database and PowerShell How-to ebook, part of Packt Publishing‘s Instant book series. Packt’s Instant book series promises short, fast, and focused information; Hudik’s book delivers. It’s eighty pages deliver hundreds of pages worth of the author’s knowledge in a highly-condensed format, perfect for today’s multi-tasking technical professionals.

Hudik’s book is ideal for anyone experienced with the Oracle Database 11g platform, and interested in leveraging Microsoft’s PowerShell scripting technology to automate their day-to-day database tasks. Even a seasoned developer, experienced in both technologies, will gain from the author’s insight on overcoming several PowerShell and .NET framework related integration intricacies.

As a busy developer, I was able to immediately start implementing many of the book’s recipes to improve my productivity. I especially enjoyed the way the book builds upon previous lessons, resulting in a useful collection of foundational PowerShell scripts and modules. Building on top of these, save time when automating a new task.

image

Getting started with the book’s examples required a few free downloads from Oracle and Microsoft. Starting with a Windows 7 Enterprise laptop, I downloaded and installed Oracle Database 11g Express Edition (Oracle Database XE) Release 2,
Oracle Developer Tools for Visual Studio, and Oracle SQL Developer IDE. I also made sure my laptop was up-to-date with the latest Visual Studio 2012, .NET framework, and PowerShell updates.
If you are new to administering Oracle databases or using Oracle SQL Developer IDE, Oracle has some excellent interactive tutorials online to help you get started.

, , , , ,

Leave a Comment

Setting Up the Nexus 7 for Development with ADT on Ubuntu

Recently, I purchased a Google Nexus 7. Excited to being development with this Android 4.2 device, I first needed to prepare my development environment. The process of configuring my Ubuntu Linux-based laptop to debug directly on the Nexus 7 was fairly easy once I identified all necessary steps. I thought I would share my process for those who are trying to do the same. Note the following steps assume you already have Java installed on you development computer. Also, that your Nexus 7 is connected via USB.

Configuration

1) Install ADT Bundle: Download and extract the Android Developer Tools (ADT) Bundle from http://developer.android.com/sdk/index.html. I installed the Linux 64-bit version for use on my Ubuntu 12.10 laptop. The bundle, according to the website, includes ‘the essential Android SDK components and a version of the Eclipse IDE with built-in ADT to streamline your Android app development.’

2) Install IA32 Libraries: Install the ia32 shared libraries using Synaptic Package Manager, or the following command, ‘sudo apt-get install ia32-libs’. I received some initial errors with ADT, until I found a post on Stack Overflow that suggested loading the libraries; they did the trick.

3) Configure Nexus 7 to Auto-Mount: To auto-mount the Nexus 7 on your computer, you need to make some changes to your computer’s system configuration. Follow this post to ‘configure your Ubuntu computer to directly access your Nexus 7 exported filesystem in MTP mode as soon as you plug it to a USB port.’, ‘http://bernaerts.dyndns.org/linux/247-ubuntu-automount-nexus7-mtp‘. It looked a bit intimidating at first, but it actually turned out to be pretty easy and only took a few minutes.

Mounting Nexus 7 on Desktop

Nexus 7 Device Mounted on Desktop via USB

4) Setup ADT to Debug Nexus 7: To debug on the Nexus 7 from ADT via USB, according to this next post, ‘you need to add a udev rules file that contains a USB configuration for each type of device you want to use for development.’ Follow the steps in this post, ‘http://developer.android.com/tools/device.html‘ to create the rules file, similar to step 3.

Adding the Android Debug Rule (step 4)

Adding the Android Debug Rule (step 4)

5) Setup Nexus 7 for USB Debugging: The post mentioned in step 4 also discusses setting up you Nexus 7 to enable USB debugging. The post instructs you to ‘go to Settings > About phone and tap ‘Build number seven times. Return to the previous screen to find Developer options.’ From there, check the ‘USB debugging’ box. There are any more options you may wish to experiment with, later.

Displaying the Nexus 7 Developer Options (step 5)

Displaying the Nexus 7 Developer Options (step 5)

Confirming USB Debugging is Connected on Nexus 7

Confirming USB Debugging is Connected on Nexus 7

6) Update you Software: After these first five steps, I suggest updating your software and restarting your computer. Run the following command to make sure your system is up-to-date, ‘sudo apt-get update && sudo apt-get upgrade’. I always run this before and after any software installations to make sure my system is current.

After completing step 3, the Nexus 7 device should appear on your Launcher. However, it is not until steps 4 and 5 that it will appear in ADT.

Demonstration

Below is a simple demonstration of  debugging an Android application on the Nexus 7 from ADT, via USB. Although ADT allows you to configure an Android Virtual Device (AVD), direct debugging on the Nexus 7 is substantially faster. The Nexus 7 AVD emulation was incredibly slow, even on my 64-bit, Core i5 laptop.

Creating a Simple 'Hello World' Application in ADT

Creating a Simple ‘Hello World’ Application in ADT

Choosing the Nexus 7 from Android Device Chooser

Choosing the Nexus 7 from Android Device Chooser

Debugging the Hello World Application on Nexus 7

Debugging the Hello World Application on Nexus 7

, , , , , , , , ,

1 Comment

Duplicating Your Raspberry Pi’s SDHC Card

There are a few reasons you might want to duplicate (clone/copy) your Raspberry Pi’s Secure Digital High-Capacity (SDHC) card. I had two, backup and a second Raspberry Pi. I spent untold hours installing and configuring software on your Raspberry Pi with Java, OpenCV, Motion, etc. Having a backup of all my work seemed like a good idea.

Second reason, a second Raspberry Pi. I wanted to set up a second Raspberry Pi, but didn’t want to spend the time to duplicate my previous efforts. Nor, could I probably ever duplicate the first Pi’s configuration, exactly. To ensure consistency across multiple Raspberry Pi’s, duplicating my first Raspberry Pi’s SDHC card made a lot of sense.

I found several posts on the web about duplicating an SDHC card. One of the best articles was on the PIXHAWK website. It only took me a few simple steps to backup my original 8 GB SDHC card, and then create a clone by copying the backup to a new 8 GB SDHC card, as follows:

1) Remove the original SDHC card from Raspberry Pi and insert it into a card reader on your computer. I strongly suggest locking the card to protect it against any mistakes while backing up.

2) Locate where the SDHC card is mounted on your computer. This can be done using GParted, or in a terminal window, using the ‘blkid’  (block device attributes) command. My Raspberry Pi’s SDHC card, with its three separate partitions was found at ‘/dev/sdb’.

GParted View of SDHC Card

GParted View of SDHC Card

Terminal Window View of Partitions

Terminal Window View of Partitions

3) Use the ‘dd’ (convert and copy a file) command to duplicate the contents of the SDHC card to your computer. This can take a while and there is no progress bar. The command I used to back up the card to my computer’s $HOME directory was:

sudo dd if=dev/sdb of=~/sdhc-card-bu.bin

4) Unmount and unlock the original SDHC card. Mount the new SDHC card. It should mount in the same place.

5) Reverse the process by copying the backup file, ‘sdhc-card-bu.bin’, to the new SDHC card. Again, this can take a while and there is no progress bar. The command I used was:

sudo dd if=~/sdhc-card-bu.bin of=/dev/sdb

Using ‘dd’, backups and restores the entire SDHC card, partitions and all. I was able to insert the card into a brand new Raspberry Pi and boot it up, without any problems.

Obviously, there are some things you may want to change on a cloned Raspberry Pi. For example, you should change the cloned Raspberry Pi’s host name, so it doesn’t conflict with the original Raspberry Pi on the network. This is easily done:

sudo nano /etc/hostname
sudo /etc/init.d/hostname.sh start

Also, changing the cloned Raspberry Pi’s root password is a wise idea for both security and sanity, especially if you have more than one Pi on your network. This guarantees you know which one you are logging into. This is easily done using the ‘passwd’ command:

Changing the Root Password on Raspberry Pi

Changing the Root Password on Raspberry Pi

, , , , , , , , ,

1 Comment

Object Tracking on the Raspberry Pi with C++, OpenCV, and cvBlob

Use C++ with OpenCV and cvBlob to perform image processing and object tracking on the Raspberry Pi, using a webcam.

A complete copy of all the code for this article is available on DropBox. The DropBox location contains the complete NetBeans project, along with compiled versions for both Intel x86_64 and ARM architectures in separate packages. If you like DropBox, please use this link to sign up for a free 2GB account. It will help me post more files to DropBox for future posts.

Introduction

As part of a project with a local FIRST Robotics Competition (FRC) Team, I’ve been involved in the development of a Computer Vision application for use on the Raspberry Pi. Our FRC team’s goal is to develop an object tracking and target acquisition application that could be run on the Raspberry Pi, as opposed to the robot’s primary embedded processor, a National Instrument’s NI cRIO-FRC II. We chose to work in C++ for it’s speed, We also decided to test two popular open-source Computer Vision (CV) libraries, OpenCV and cvBlob.

Due to its single ARM1176JZF-S 700 MHz ARM processor, a significant limitation of the Raspberry Pi is the ability to perform complex operations in real-time, such as image processing. In an earlier post, I discussed Motion to detect motion with a webcam on the Raspberry Pi. Although the Raspberry Pi was capable of running Motion, it required a greatly reduced capture size and frame-rate. And even then, the Raspberry Pi’s ability to process the webcam’s feed was very slow. I had doubts it would be able to meet the processor-intense requirements of this project.

Development for the Raspberry Pi

Using C++ in NetBeans 7.2.1 on Ubuntu 12.04.1 LTS and 12.10, I wrote several small pieces of code to demonstrate the Raspberry Pi’s ability to perform basic image processing and object tracking. Parts of the follow code are based on several OpenCV and cvBlob code examples I found in my research. Many of those examples are linked on the end of this article. Examples of cvBlob are especially hard to find.

Project in NetBeans

Project in NetBeans

After writing the code, the first big challenge was cross-compiling the native C++ code, written on Intel IA-32 and 64-bit x86-64 processor-based laptops, to run on the Raspberry Pi’s ARM architecture. After failing to successfully cross-compile the C++ source code using crosstools-ng, mostly due to my lack of cross-compiling experience, I resorted to using g++ to compile the C++ source code directly on the Raspberry Pi. To do so, I first had to properly install the various CV libraries and the compiler on the Raspberry Pi, which itself can be a bit daunting. Compiling OpenCV 2.4.3, from the source-code, on the Raspberry Pi took an astounding 8 hours. Even though compiling the C++ source code takes longer on the Raspberry Pi, I could be assured the complied code would run locally.

Testing OpenCV and cvBlob

The code examples below contain three pair of tests (six total), as follows:

  1. Basic OpenCV – Determine if OpenCV is installed and functioning properly with the complied C++ code. Capture a webcam feed using OpenCV, and display the feed and frame rate (fps).
  2. Basic OpenCV – Same as Test #1, but only print the frame rate (fps). The computer doesn’t need the feed displayed to process the data. More importantly, the webcam’s feed might unnecessarily tax the computer’s processor and GPU.
  3. Basic OpenCV and cvBlob – Determine if OpenCV and cvBlob are installed and functioning properly with the complied C++ code. Detect and display all objects (blobs) in a specific red color range, contained in a static jpeg image.
  4. Basic OpenCV and cvBlob – Same as Test #3, but only print some basic information about the static image and quantity of blobs detected.
  5. Basic Object Tracking – Detect, track, and display all objects (blobs) in a specific blue color range, along with the largest blob’s positional data. Captured with a webcam, using OpenCV and cvBlob.
  6. Basic Object Tracking – Same as Test #4, but only display the largest blob’s positional data. Again, the computer doesn’t need the display the webcam feed, to process the data. The feed taxes the computer’s processor unnecessarily, which is being consumed with detecting and tracking the blobs. The blob’s positional data it sent to the robot and used by its targeting system to position its shooting component.
Test 1: Displaying Feed from Webcam using OpenCV (laptop)

Test 1: Displaying Feed from Webcam using OpenCV (laptop)

Test 1: Displaying Feed from Webcam using OpenCV (Raspberry Pi)

Test 1: Displaying Feed from Webcam using OpenCV (Raspberry Pi)

Test 3: Detecting Objects within a Red Color Range on a Static Image Using OpenCV and cvBlob (laptop)

Test 3: Detecting Objects within Red Color Range in Static Image using OpenCV and cvBlob (laptop)

Test 3: Detecting Objects within Red Color Range in Static Image using OpenCV and cvBlob (Raspberry Pi)

Test 3: Detecting Objects within Red Color Range in Static Image using OpenCV and cvBlob (Raspberry Pi)

Test 5: Detecting Objects within Blue Color Range from Webcam Feed using OpenCV and cvBlob (laptop)

Test 5: Detecting Objects within Blue Color Range from Webcam Feed using OpenCV and cvBlob (laptop)

Test 5: Detecting Objects within Blue Color Range from Webcam Feed using OpenCV and cvBlob (Raspberry Pi)

Test 5: Detecting Objects within Blue Color Range from Webcam Feed using OpenCV and cvBlob (Raspberry Pi)

The Results

Each test was first run on two Linux-based laptops, with Intel 32-bit and 64-bit architectures, and with two different USB webcams. The laptops were used to develop and test the code, as well as provide a baseline for application performance. Many factors can dramatically affect the application’s ability do image processing. They include the computer’s processor(s), RAM, HDD, GPU, USB, Operating System, and the webcam’s video capture size, compression ratio, and frame-rate. There are significant differences in all these elements when comparing an average laptop to the Raspberry Pi.

Frame-rates on the Intel processor-based Ubuntu laptops easily performed at or beyond the maximum 30 fps rate of the webcams, at 640 x 480 pixels. On a positive note, the Raspberry Pi was able to compile and execute the tests of OpenCV and cvBlob (see bug noted at end of article). Unfortunately, at least in my tests, the Raspberry Pi could not achieve more than 1.5 – 2 fps at most, even in the most basic tests, and at a reduced capture size of 320 x 240 pixels. This can be seen in the first and second screen-grabs of Test #1, above. Although, I’m sure there are ways to improve the code and optimize the image capture, the results were much to slow to provide accurate, real-time data to the robot’s targeting system.

The Code

The code is divided amongst five C++ files, ‘main.cpp’, ‘testfps.cpp (testfps.h)’, and ‘testcvblob.cpp (testcvblob.h)’. The file, main.cpp, calls the test methods in the other two files. There are two ways to run this program. Firstly, from the command line you can call the application and pass in three parameters. The parameters include 1) the test method you want to run (1-6), 2) the width of the webcam capture window in pixels, and 3) the height of the webcam capture window in pixels. An example would be ‘./TestFps 2 640 480′ or ‘./TestFps 5 320 240′. The second method to run the program and not pass in any parameters. In that case, the program will prompt you to input the test number and other parameters on screen.

Input Options for Application

Input Options for Application

Note, the code is not written using the latest OpenCV 2.0 conventions. Because cvBlob only works with the pre-OpenCV 2.0 conventions, I wrote all the code using the older objects and methods. For example, cvBlob uses 1.0′s ‘IplImage’ image type instead 2.0′s newer ‘CvMat’ image type. My next projects is to re-write the cvBlob code to use OpenCV 2.0 conventions and/or find a newer library. The cvBlob library offered so many advantages, I felt not using the newer OpenCV 2.0 features was still worthwhile.

Main Program Method (main.cpp):

/* 
 * File:        main.cpp
 * Author:      Gary Stafford
 * Description: Program entry point
 * Created:     February 3, 2013
 */

#include <stdio.h>
#include <sstream>
#include <stdlib.h>
#include <iostream>

#include "testfps.h"
#include "testcvblob.h"

using namespace std;

int main(int argc, char* argv[]) {
    /*Camera size choices
        640 x 480
        352 x 288 (320 x 240)
        176 x 144 (160 x 120)
     */

    int captureMethod = 0;
    int captureWidth = 0;
    int captureHeight = 0;

    if (argc == 4) { // user input parameters with call
        captureMethod = strtol(argv[1], NULL, 0);
        captureWidth = strtol(argv[2], NULL, 0);
        captureHeight = strtol(argv[3], NULL, 0);

    } else { // user did not input parameters with call
        cout << endl << "Demonstrations/Tests: " << endl;
        cout << endl << "(1) Test OpenCV - Show Webcam" << endl;
        cout << endl << "(2) Test OpenCV - No Webcam" << endl;
        cout << endl << "(3) Test cvBlob - Show Image" << endl;
        cout << endl << "(4) Test cvBlob - No Image" << endl;
        cout << endl << "(5) Test Blob Tracking - Show Webcam" << endl;
        cout << endl << "(6) Test Blob Tracking - No Webcam" << endl;
        cout << endl << "Input test # (1-6): ";
        cin >> captureMethod;

        // test 3 and 4 don't require width and height parameters
        if (captureMethod != 3 && captureMethod != 4) {
            cout << endl << "Input capture width (pixels): ";
            cin >> captureWidth;
            cout << endl << "Input capture height (pixels): ";
            cin >> captureHeight;
            cout << endl;

            if (!captureWidth > 0) {
                cout << endl << "Width value incorrect" << endl;
                return -1;
            }

            if (!captureHeight > 0) {
                cout << endl << "Height value incorrect" << endl;
                return -1;
            }
        }
    }

    switch (captureMethod) {
        case 1:
            TestFpsShowVideo(captureWidth, captureHeight);
        case 2:
            TestFpsNoVideo(captureWidth, captureHeight);
            break;
        case 3:
            DetectBlobsShowStillImage();
            break;
        case 4:
            DetectBlobsNoStillImage();
            break;
        case 5:
            DetectBlobsShowVideo(captureWidth, captureHeight);
            break;
        case 6:
            DetectBlobsNoVideo(captureWidth, captureHeight);
            break;
        default:
            break;
    }
    return 0;
}

Tests 1 and 2 (testfps.cpp):

/* 
 * File:        testfps.cpp
 * Author:      Gary Stafford
 * Description: Test the fps of a webcam using OpenCV
 * Created:     February 3, 2013
 */

#include <cv.h>    
#include <highgui.h>
#include <time.h>
#include <stdio.h>

#include "testfps.h"

using namespace std;

int TestFpsNoVideo(int captureWidth, int captureHeight) {
    IplImage* frame;
    CvCapture* capture = cvCreateCameraCapture(-1);
    cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, captureWidth);
    cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, captureHeight);

    time_t start, end;
    double fps, sec;
    int counter = 0;
    char k;

    time(&start);

    while (1) {
        frame = cvQueryFrame(capture);
        time(&end);
        ++counter;
        sec = difftime(end, start);
        fps = counter / sec;
        printf("FPS = %.2f\n", fps);

        if (!frame) {
            printf("Error");
            break;
        }

        k = cvWaitKey(10)&0xff;
        switch (k) {
            case 27:
            case 'q':
            case 'Q':
                break;
        }
    }

    cvReleaseCapture(&capture);
    
    return 0;
}

int TestFpsShowVideo(int captureWidth, int captureHeight) {
    IplImage* frame;
    CvCapture* capture = cvCreateCameraCapture(-1);
    cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, captureWidth);
    cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, captureHeight);
    cvNamedWindow("Webcam Preview", CV_WINDOW_AUTOSIZE);
    cvMoveWindow("Webcam Preview", 300, 200);

    time_t start, end;
    double fps, sec;
    int counter = 0;
    char k;

    time(&start);

    while (1) {
        frame = cvQueryFrame(capture);
        time(&end);
        ++counter;
        sec = difftime(end, start);
        fps = counter / sec;
        printf("FPS = %.2f\n", fps);

        if (!frame) {
            printf("Error");
            break;
        }

        cvShowImage("Webcam Preview", frame);

        k = cvWaitKey(10)&0xff;
        switch (k) {
            case 27:
            case 'q':
            case 'Q':
                break;
        }
    }

    cvDestroyWindow("Webcam Preview");
    cvReleaseCapture(&capture);
    
    return 0;
}

Tests 3-6 (testcvblob.cpp):

/* 
 * File:        testcvblob.cpp
 * Author:      Gary Stafford
 * Description: Track blobs using OpenCV and cvBlob
 * Created:     February 3, 2013
 */

#include <cv.h>
#include <highgui.h>
#include <cvblob.h>

#include "testcvblob.h"

using namespace cvb;
using namespace std;

int DetectBlobsNoStillImage() {
    /// Variables /////////////////////////////////////////////////////////
    CvSize imgSize;
    IplImage *image, *segmentated, *labelImg;
    CvBlobs blobs;

    unsigned int result = 0;
    ///////////////////////////////////////////////////////////////////////

    image = cvLoadImage("colored_balls.jpg");

    if (image == NULL) {
        return -1;
    }

    imgSize = cvGetSize(image);
    cout << endl << "Width (pixels): " << image->width;
    cout << endl << "Height (pixels): " << image->height;
    cout << endl << "Channels: " << image->nChannels;
    cout << endl << "Bit Depth: " << image->depth;
    cout << endl << "Image Data Size (kB): " 
            << image->imageSize / 1024 << endl << endl;

    segmentated = cvCreateImage(imgSize, 8, 1);
    
    cvInRangeS(image, CV_RGB(155, 0, 0), CV_RGB(255, 130, 130), segmentated);
    
    labelImg = cvCreateImage(cvGetSize(image), IPL_DEPTH_LABEL, 1);
    
    result = cvLabel(segmentated, labelImg, blobs);
    
    cvFilterByArea(blobs, 500, 1000000);

    cout << endl << "Blob Count: " << blobs.size();
    cout << endl << "Pixels Labeled: " << result << endl << endl;

    cvReleaseBlobs(blobs);

    cvReleaseImage(&labelImg);
    cvReleaseImage(&segmentated);
    cvReleaseImage(&image);

    return 0;
}

int DetectBlobsShowStillImage() {
    /// Variables /////////////////////////////////////////////////////////
    CvSize imgSize;
    IplImage *image, *frame, *segmentated, *labelImg;
    CvBlobs blobs;

    unsigned int result = 0;
    bool quit = false;
    ///////////////////////////////////////////////////////////////////////

    cvNamedWindow("Processed Image", CV_WINDOW_AUTOSIZE);
    cvMoveWindow("Processed Image", 750, 100);
    cvNamedWindow("Image", CV_WINDOW_AUTOSIZE);
    cvMoveWindow("Image", 100, 100);

    image = cvLoadImage("colored_balls.jpg");

    if (image == NULL) {
        return -1;
    }

    imgSize = cvGetSize(image);
    cout << endl << "Width (pixels): " << image->width;
    cout << endl << "Height (pixels): " << image->height;
    cout << endl << "Channels: " << image->nChannels;
    cout << endl << "Bit Depth: " << image->depth;
    cout << endl << "Image Data Size (kB): " 
            << image->imageSize / 1024 << endl << endl;

    frame = cvCreateImage(imgSize, image->depth, image->nChannels);

    cvConvertScale(image, frame, 1, 0);

    segmentated = cvCreateImage(imgSize, 8, 1);

    cvInRangeS(image, CV_RGB(155, 0, 0), CV_RGB(255, 130, 130), segmentated);
    cvSmooth(segmentated, segmentated, CV_MEDIAN, 7, 7);

    labelImg = cvCreateImage(cvGetSize(frame), IPL_DEPTH_LABEL, 1);

    result = cvLabel(segmentated, labelImg, blobs);
    cvFilterByArea(blobs, 500, 1000000);
    cvRenderBlobs(labelImg, blobs, frame, frame,
            CV_BLOB_RENDER_BOUNDING_BOX | CV_BLOB_RENDER_TO_STD, 1.);

    cvShowImage("Image", frame);
    cvShowImage("Processed Image", segmentated);

    while (!quit) {
        char k = cvWaitKey(10)&0xff;
        switch (k) {
            case 27:
            case 'q':
            case 'Q':
                quit = true;
                break;
        }
    }
    cvReleaseBlobs(blobs);

    cvReleaseImage(&labelImg);
    cvReleaseImage(&segmentated);
    cvReleaseImage(&frame);
    cvReleaseImage(&image);

    cvDestroyAllWindows();

    return 0;
}

int DetectBlobsNoVideo(int captureWidth, int captureHeight) {
    /// Variables /////////////////////////////////////////////////////////
    CvCapture *capture;
    CvSize imgSize;

    IplImage *image, *frame, *segmentated, *labelImg;
    int picWidth, picHeight;

    CvTracks tracks;
    CvBlobs blobs;
    CvBlob* blob;

    unsigned int result = 0;

    bool quit = false;
    ///////////////////////////////////////////////////////////////////////

    capture = cvCaptureFromCAM(-1);
    cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, captureWidth);
    cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, captureHeight);
    cvGrabFrame(capture);
    image = cvRetrieveFrame(capture);

    if (image == NULL) {
        return -1;
    }

    imgSize = cvGetSize(image);
    cout << endl << "Width (pixels): " << image->width;
    cout << endl << "Height (pixels): " << image->height << endl << endl;

    frame = cvCreateImage(imgSize, image->depth, image->nChannels);

    while (!quit && cvGrabFrame(capture)) {
        image = cvRetrieveFrame(capture);

        cvConvertScale(image, frame, 1, 0);

        segmentated = cvCreateImage(imgSize, 8, 1);

        cvInRangeS(image, CV_RGB(155, 0, 0), CV_RGB(255, 130, 130), segmentated);
        cvSmooth(segmentated, segmentated, CV_MEDIAN, 7, 7);

        labelImg = cvCreateImage(cvGetSize(frame), IPL_DEPTH_LABEL, 1);

        result = cvLabel(segmentated, labelImg, blobs);
        cvFilterByArea(blobs, 500, 1000000);
        cvRenderBlobs(labelImg, blobs, frame, frame, 0x000f, 1.);
        cvUpdateTracks(blobs, tracks, 200., 5);
        cvRenderTracks(tracks, frame, frame, 0x000f, NULL);

        picWidth = frame->width;
        picHeight = frame->height;

        if (cvGreaterBlob(blobs)) {
            blob = blobs[cvGreaterBlob(blobs)];

            cout << "Blobs found: " << blobs.size() << endl;
            cout << "Pixels labeled: " << result << endl;
            cout << "center-x: " << blob->centroid.x
                    << "   center-y: " << blob->centroid.y
                    << endl;
            cout << "offset-x: " << ((picWidth / 2)-(blob->centroid.x))
                    << "   offset-y: " << (picHeight / 2)-(blob->centroid.y)
                    << endl;
            cout << "\n";
        }

        char k = cvWaitKey(10)&0xff;
        switch (k) {
            case 27:
            case 'q':
            case 'Q':
                quit = true;
                break;
        }
    }

    cvReleaseBlobs(blobs);

    cvReleaseImage(&labelImg);
    cvReleaseImage(&segmentated);
    cvReleaseImage(&frame);
    cvReleaseImage(&image);

    cvDestroyAllWindows();

    cvReleaseCapture(&capture);

    return 0;
}

int DetectBlobsShowVideo(int captureWidth, int captureHeight) {
    /// Variables /////////////////////////////////////////////////////////
    CvCapture *capture;
    CvSize imgSize;

    IplImage *image, *frame, *segmentated, *labelImg;
    CvPoint pt1, pt2, pt3, pt4, pt5, pt6;
    CvScalar red, green, blue;
    int picWidth, picHeight, thickness;

    CvTracks tracks;
    CvBlobs blobs;
    CvBlob* blob;

    unsigned int result = 0;

    bool quit = false;
    ///////////////////////////////////////////////////////////////////////

    cvNamedWindow("Processed Video Frames", CV_WINDOW_AUTOSIZE);
    cvMoveWindow("Processed Video Frames", 750, 400);
    cvNamedWindow("Webcam Preview", CV_WINDOW_AUTOSIZE);
    cvMoveWindow("Webcam Preview", 200, 100);

    capture = cvCaptureFromCAM(-1);
    cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, captureWidth);
    cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, captureHeight);
    cvGrabFrame(capture);
    image = cvRetrieveFrame(capture);

    if (image == NULL) {
        return -1;
    }

    imgSize = cvGetSize(image);
    cout << endl << "Width (pixels): " << image->width;
    cout << endl << "Height (pixels): " << image->height << endl << endl;

    frame = cvCreateImage(imgSize, image->depth, image->nChannels);

    while (!quit && cvGrabFrame(capture)) {
        image = cvRetrieveFrame(capture);

        cvConvertScale(image, frame, 1, 0);

        segmentated = cvCreateImage(imgSize, 8, 1);

        cvInRangeS(image, CV_RGB(36, 43, 89), CV_RGB(86, 132, 209), segmentated);
        cvSmooth(segmentated, segmentated, CV_MEDIAN, 7, 7);

        labelImg = cvCreateImage(cvGetSize(frame), IPL_DEPTH_LABEL, 1);

        result = cvLabel(segmentated, labelImg, blobs);
        cvFilterByArea(blobs, 500, 1000000);
        cvRenderBlobs(labelImg, blobs, frame, frame,
                CV_BLOB_RENDER_BOUNDING_BOX | CV_BLOB_RENDER_COLOR, 1.);
        cvUpdateTracks(blobs, tracks, 200., 5);
        cvRenderTracks(tracks, frame, frame, CV_TRACK_RENDER_BOUNDING_BOX, NULL);

        red = CV_RGB(250, 0, 0);
        green = CV_RGB(0, 250, 0);
        blue = CV_RGB(0, 0, 250);

        thickness = 1;
        picWidth = frame->width;
        picHeight = frame->height;

        pt1 = cvPoint(picWidth / 2, 0);
        pt2 = cvPoint(picWidth / 2, picHeight);
        cvLine(frame, pt1, pt2, red, thickness);

        pt3 = cvPoint(0, picHeight / 2);
        pt4 = cvPoint(picWidth, picHeight / 2);
        cvLine(frame, pt3, pt4, red, thickness);

        cvShowImage("Webcam Preview", frame);
        cvShowImage("Processed Video Frames", segmentated);

        if (cvGreaterBlob(blobs)) {
            blob = blobs[cvGreaterBlob(blobs)];
            pt5 = cvPoint(picWidth / 2, picHeight / 2);
            pt6 = cvPoint(blob->centroid.x, blob->centroid.y);
            cvLine(frame, pt5, pt6, green, thickness);
            cvCircle(frame, pt6, 3, green, 2, CV_FILLED, 0);

            cvShowImage("Webcam Preview", frame);
            cvShowImage("Processed Video Frames", segmentated);

            cout << "Blobs found: " << blobs.size() << endl;
            cout << "Pixels labeled: " << result << endl;
            cout << "center-x: " << blob->centroid.x
                    << "   center-y: " << blob->centroid.y
                    << endl;
            cout << "offset-x: " << ((picWidth / 2)-(blob->centroid.x))
                    << "   offset-y: " << (picHeight / 2)-(blob->centroid.y)
                    << endl;
            cout << "\n";
        }

        char k = cvWaitKey(10)&0xff;
        switch (k) {
            case 27:
            case 'q':
            case 'Q':
                quit = true;
                break;
        }
    }

    cvReleaseBlobs(blobs);

    cvReleaseImage(&labelImg);
    cvReleaseImage(&segmentated);
    cvReleaseImage(&frame);
    cvReleaseImage(&image);

    cvDestroyAllWindows();

    cvReleaseCapture(&capture);

    return 0;
}

Compiling Locally on the Raspberry Pi

You will need a good understanding how to compile C++ from the commandline to implement the above code. Below are the commands that I used to transfer and compile my C++ source code on the Raspberry Pi. They should aid you, once you have the compiler, OpenCV and cvBlob successfully installed on the Raspberry Pi.

scp *.jpg *.cpp *.h pi@192.168.XXX.XXX:your/file/path/
ssh pi@192.168.XXX.XXX
cd ~/your/file/path/
g++ `pkg-config opencv cvblob --cflags --libs` testfps.cpp testcvblob.cpp main.cpp -o FpsTest -v
./FpsTest
Compiling Program on Raspberry Pi

Compiling Program on Raspberry Pi

Special Note About cvBlob on ARM

At first I had given up on cvBlob working on the Raspberry Pi. All the cvBlob tests I ran, no matter how simple, continued to hang on the Raspberry Pi after working perfectly on my laptop. I had narrowed the problem down to the ‘cvLabel’ method, but was unable to resolve. However, I recently discovered a documented bug on the cvBlob website, regarding cvBlob and the very same ‘cvLabel’ method on ARM-based devices (ARM == Raspberry Pi!). After making a minor modification to cvBlob’s ‘cvlabel.cpp’ source code, as directed in the bug post, and re-compiling on the Raspberry Pi, the test worked perfectly.

Links of Interest

Static Test Images Free from: http://www.rgbstock.com/

Great Website for OpenCV Samples: http://opencv-code.com/

Another Good Website for OpenCV Samples: http://opencv-srf.blogspot.com/2010/09/filtering-images.html

cvBlob Code Sample: https://code.google.com/p/cvblob/source/browse/samples/red_object_tracking.cpp

Detecting Blobs with cvBlob: http://8a52labs.wordpress.com/2011/05/24/detecting-blobs-using-cvblobs-library/

Best Post/Script to Install OpenCV on Ubuntu and Raspberry Pi: http://jayrambhia.wordpress.com/2012/05/02/install-opencv-2-3-1-and-simplecv-in-ubuntu-12-04-precise-pangolin-arch-linux/

Measuring Frame-rate with OpenCV: http://8a52labs.wordpress.com/2011/05/19/frames-per-second-in-opencv/

OpenCV and Raspberry Pi: http://mitchtech.net/raspberry-pi-opencv/

, , , , , , , , , , , , , , , , , , , ,

11 Comments

Extending the Life of Older Windows Laptops with Linux

Like thousands of technology-driven consumers, our family recently upgraded an older laptop. As a Christmas gift, my daughter received an Intel Core i3 Windows laptop. The new laptop replaced her well-worn Intel Core 2 laptop. That old Core 2 was my previous development laptop. It had been upgraded from Windows XP to Windows 7 Pro. It also had its RAM increased and a bigger hard drive installed. But after a few years of heavy use, it seemed painfully slow, bloated with endless software installs and Windows updates. It was certainly too under-powered to support an upgrade to Windows 8.

With four family members usually upgrading their laptops every 3-4 years, my daughter’s old laptop was destined to join a growing stack of ‘retired’ electronics in our basement — until today. In just a few hours, I transformed that laptop into ‘mean, lean, open-source-breathing, Ubuntu-powered machine’. Okay, well maybe not that dramatic, but a signification increase in performance and lifespan non-the-less, at no cost and with minimal effort.

I am a huge fan of Oracle VM VirtualBox. I have three other machines running Linux VMs on Windows. However, a VM is no substitute for a dedicated system, especially on a laptop. There are increased system requirements to run the host’s OS, along with VirtualBox, and the VM’s OS. At the same time, there are often limitations on the VM’s OS. I had wanted a dedicated Ubuntu laptop for a while, and this was my chance.

Fresh Install of Ubuntu on Previous Windows-based Dell Laptop

Fresh Install of Ubuntu on Previous Windows-based Dell Laptop

Performance with Ubuntu

My thoughts after a month with the laptop? First the cons. Some issues transcend the operating system. Although, the battery life has improved slightly with Linux, the battery is approaching end-of-life and needs to be replaced. Also, the laptop continues to run hotter than it should. However, it doesn’t suffer the occasional shutdowns from overheating and constant loss of wireless that it did with Windows. Lastly, the screen is starting to lose it brightness, but is still usable.

The pros? Limited memory is not as much an issue with Ubuntu as is with Windows. Ubuntu starts up in a fraction of the time it took Windows. All the laptop’s components worked out of the box on Ubuntu with no driver issues. All the applications I use on Windows are also available on Ubuntu, or there are good alternatives. Lastly, using free services such as Dropbox, Ubuntu One, and Google Drive, I can author and store all my documents in the Cloud, and transfer them seamlessly between Linux and Windows when necessary. What’s not to love?

New System Performance

New System Performance

Overall, I’m satisfied enough to use it as my personal laptop. I carry the laptop with me daily for Java, C++, and Python development, emailing, blogging, and web-surfing. Next time your temped to retire an old laptop, consider extending its life and saving yourself the cost of a new laptop with Linux.

, , , , , , ,

1 Comment

Remote Motion-Activated Web-Based Surveillance with Raspberry Pi

Introduction

Ever want to keep an eye on your house while your away? Maybe observe backyard wildlife close-up? Or my favorite for IT, keep an eye on your server room? Low-end wireless IP cameras start at $50-$75 USD. Higher-end units can run into the hundreds of dollars. Add motion detection and the price raises even further. How about a lower-cost solution? Using a Raspberry Pi with an inexpensive webcam, a wireless WiFi Module, and optional battery pack, you can a remote, motion-activated camera solution, at a fraction of the cost. Best of all, you won’t need to write a single line of code or hack any electronics to get started.

_MG_9526

There are many good articles on the Web that demonstrate how to build a RaspPi-based motion-activated video solution. One of the more popular software solutions is Motion. According to their website, ‘Motion is a program that monitors the video signal from one or more cameras and is able to detect if a significant part of the picture has changed; in other words, it can detect motion‘. Motion has all the capabilities to stream images from your webcam to a built-in web server, where you can reach them through your browser, with little or no configuration. Motion is easily configured to work with streaming video apps like FFmpeg, save images to a database like mySQL or PostgreSQL, and execute external scripts such as python or shell. We are going to use Motion’s most basic features in this post, motion detection and streaming.

Installing Motion

Before installing Motion, I recommend ensuring your Raspberry Pi is up-to-date with the latest software and firmware. Updating firmware is not necessary; however I had an experience while helping someone else with their RaspPi, where their camera would not work correctly. After finding a few folks online with similar problems, we updated the firmware on the RaspPi and fixed the problem. Installing firmware can sound a bit intimidating; however, Liam McLoughlin (hexxeh) has made the process easy with rpi-update. I have used it successfully on three RaspPi’s. Three commands to update your RaspPi.

To update your RaspPi’s software, execute the following command. Note if you don’t do this on a regular basis, as recommended, these steps could take up to 5 minutes or more. Watch for errors. If there are any, just run it again. Sometimes, the RaspPi cannot connect to all sources for updates.

sudo apt-get update && sudo apt-get upgrade

Once the updates are completed successfully, install Motion by issuing the following command:

sudo apt-get install motion

Enabling Motion
As the installation completes, you should see a warning in the command shell about Motion being disabled by default.

...
Adding user `motion' to group `video' ...
Adding user motion to group video
Done.
[warn] Not starting motion daemon, disabled via /etc/default/motion ... (warning).
Setting up ffmpeg (6:0.8.4-1) ...
pi@garyrasppi ~ $

To enable Motion (the motion daemon), we need to edit the /etc/default/motion file.

sudo nano /etc/default/motion

Change the ‘start_motion_daemon‘ parameter to ‘yes’.

Enable Daemon

Configuring Motion

Motion is easy to customize, with a plethora of parameters you can tweak based on your needs. Since Motion has no GUI, configuration is all done through Motion’s configuration file (/etc/motion/motion.conf).

Before editing the configuration file we need to change the permissions on it, so Motion can access it. While we’re at it, we will also change permissions on the folder where Motion stores images.

sudo chmod -R 777 /etc/motion/motion.conf
sudo chmod -R 777 /tmp/motion

Open the configuration file in Nano with the following command.

sudo nano /etc/motion/motion.conf

Motion’s configuration file is lengthy, but broken down into sections to make finding the setting you are looking for, easy. First, we need to change the ‘Live Webcam Server’ section of configuration. Below are the default settings:

############################################################
# Live Webcam Server
############################################################

# The mini-http server listens to this port for requests (default: 0 = disabled)
webcam_port 8081

# Quality of the jpeg (in percent) images produced (default: 50)
webcam_quality 50

# Output frames at 1 fps when no motion is detected and increase to the
# rate given by webcam_maxrate when motion is detected (default: off)
webcam_motion off

# Maximum framerate for webcam streams (default: 1)
webcam_maxrate 1

# Restrict webcam connections to localhost only (default: on)
webcam_localhost on

# Limits the number of images per connection (default: 0 = unlimited)
# Number can be defined by multiplying actual webcam rate by desired number of seconds
# Actual webcam rate is the smallest of the numbers framerate and webcam_maxrate
webcam_limit 0

The first thing you will want to change is Motion’s default setting that restricts image streaming to ‘localhost‘, only. This means you can only view images in a web browser on the RaspPi, not remotely on your LAN. Change that line of code to read ‘webcam_localhost off‘.

The next setting I recommend changing for security purposes is the default port Motion uses to stream images, port 8081. Change this port to another random port, for example, 6789 (‘webcam_port 6789‘). This means if your RaspPi’s wireless IP address is 192.169.1.9, images from your webcam should be accessible at 192.169.1.4:6789. If you plan on making the webcam’s images available over the Internet, I definitely recommend changing the port. Security through obscurity is better than no security at all.

The other two settings in this section you can play with are the webcam quality and maximum framerate. You will have to adjust this based on your network speed and the processing power of your RaspPi. The default settings are a good place to start. I changed my quality from the default of 50 to 80 (‘webcam_quality 80‘), and I changed my max framerate to 2 (‘webcam_maxrate 2‘).

Speaking of quality, the other two settings you may want to change are the width and height of the image being captured by motion. This is done in the ‘Capture device options’ section. As the file’s comments suggest, these settings are dependent on your camera. Check the camera’s available image sizes; you will need to use one of those size combinations. I have mine set to an average size of 352 x 288. You may want a smaller image with a slower network, Internet streaming, or when accessing via a smart phone web browser. Conversely, a larger image is better for viewing on your local LAN. Image size, like compression quality, and framerate are dependent on processing power of your RaspPi and its OS (Raspbian, Debian, Arch, etc.). You may need to play with these settings to get the desired results. I couldn’t stream images larger than 352 x 288, even though my webcam could go up to 640 x 480.

<pre># Image width (pixels). Valid range: Camera dependent, default: 352
width 352

# Image height (pixels). Valid range: Camera dependent, default: 288
height 288

It’s important to remember, each time you make changes to Motion’s configuration file, you must restart Motion, using the following command.

sudo /etc/init.d/motion restart

Viewing Your Webcam Remotely

To view your webcam’s output from another device on your LAN, point your web browser to the IP address of your RaspPi and the port you assigned in Motion’s configuration file. Motion may take up to 15-20 seconds to start responding in the browser. If it takes much longer, you probably have your image size, framerate, and compression settings to high for your RaspPi.

Viewing Your Webcam Over the Internet
Viewing your webcam’s output over the Internet can be relativity easy or totally impossible, depending on your router and your Internet provider. In my case, I configured port-forwarding on my Netgear Wireless Router. In the example below, I created port-forwarding rule, which allows all external HTTP requests to port ’3456′ to be forwarded to internal port ’6789′, which is the streaming port for Motion on my RaspPi.

For example, let’s say the internal address of my RaspPi on my LAN is 192.168.1.9, and my external Internet IP address if 113.45.67.88. I go down to the local coffee shop and decide to check if the mailman has delivered my new Raspberry pi to my front porch. I enter http://113.45.67.88:3456 in my phone’s web browser. My home router receives the request and forwards it to 192.168.1.9:6789, which returns a stream of still images to my phone at the coffee shop. Still no RaspPi, so sad…

So what is the external address of my network? I checked the Internet port’s IP address in the Netgear’s Router Status window. Since I do not pay my Internet-provider for a static IP address, the address I am assigned is dynamic. It can and will change, sometimes almost never, sometimes daily; it depends on your provider. To view your webcam’s images, you will have to know your current Internet port’s IP address. User this address, with the external port you used for port-forwarding.

Netgear Port Forwarding

Motion Examples
Here are some example from my Microsoft LifeCam VX-500 webcam. The highest quality I could consistently get from my RaspPi 512Mb Model B, with both Soft-float Debian “wheezy” and Raspbian “wheezy”, was 352 x 288 at 80% compression and 2 fsp max. Note I’ve turned on a few more of Motion’s options in the images below, including pixel change count, camera name, and the ‘locate box’, which tracks the exact area within the image that is moving. The first three are from my laptop, on my LAN. The last is from my iPhone while shopping at the local grocery store. My wife was pretty impressed with my port-forwarding knowledge. OK, not really…

Front Enterence

Capture2

iPhone Scaled

Useful Links

Here are a few links to other useful articles on the use of Motion with the Raspberry Pi:

Setup a webcam security system with Ubuntu Linux and Motion

Guest blog #7: Bird table webcam by Francis Agius

Raspberry Pi webcam

motion(1) – Linux man page (good source for understand Motion config)

Linux UVC Supported Devices (a good starting point for buying a webcam)

, , , , , , , , , , , , , , ,

15 Comments

Follow

Get every new post delivered to your Inbox.

Join 301 other followers