Monday, April 25, 2016

Android Studio: easier text string extraction from a layout file into a string resource XML file

All the while in Android Studio, I individually create and populate a strings resource XML file, then link the named strings to the layout XML file using the @string/string_name construct. Then I found that Android Studio has a convenient helper function to extract the text string from the layout XML file and placed it into the strings resource XML file. That function is the Extract String Resource command, and the following steps show how to use it.

  1. In Android Studio, open up a layout XML file. Place the cursor on the line with the text you want to extract e.g. android:title="My title", as shown in the screenshot below.


  2. Wait for the light bulb to appear, then either click on it or press ALT+ENTER.

    A context menu appears.

  3. Chose Extract String Resource.

    The Extract Resource dialog appears.

  4. In the Resource name field, type in a label e.g. my_title.

    Optional. Change the file name, resource directories, or create new resource directories.
  5. Press OK.

    The text in the layout is extracted into the selected string resource XML file.

Monday, April 18, 2016

Publish and deploy a C# Web Service API to IIS

After developing a Web Service API application in Visual Studio, the next step may be to publish and deploy the application to an Internet Information Server (IIS). Applications can be published as a package zip file, written straight to the file system, or uploaded to the Cloud provider Azure. In this example, I will publish to a package zip file, then deploy the package to IIS.

  1. In Visual Studio's Solution Explorer pane, right click on the Web Service API project e.g. ProductsAPP.

  2. In the pop up menu, choose Publish.

    The Publish Web dialog box appears.

    Note: if a profile has been created, the following screen will appear.
  3. In the Target list, choose Custom. Click Next.

    The New Custom Profile prompt appears.

  4. Type in a profile name, e.g. ProductsAppProfile. Click OK.


  5. In the Publish method field, choose Web Deploy Package. In the Package location, type in or browse to select a destination folder, e.g. D:\Temp\.
  6. Optional: Type in a Site name e.g. ProductsApp. Click Next.

  7. Click Publish.

    The package zip file is created
    .
Once the package zip file is created, it can then be deployed onto a supported IIS platform.

  1. On the web server, start the Internet Information Services (IIS) Manager by clicking Start | Control Panel | Administrative Tools | Internet Information Services (IIS) Manager.


  2. In the Connection pane, expand the node.
  3. Optional. Select Application Pools to check the pools whether they are running on .NET Framework 4+.



    If the pool is running on Framework 2+, Framework 4+ must be installed. Then for each pool, select Basic Settings on the right and change to Framework 4+, as shown below.

  4. In the Connection pane, select a web site node e.g. Default web site.


  5.  In the Deploy section on the right, click Import Application.

    Note: if there is no Import Application, then the Web Deployment Tool has to be installed. On my IIS 7+ system, I had to use version 2.1 to get the deploy commands. Versions 3.5 and Version 3.6 did not come with the Deploy commands.

    The Import Application Package dialog box appears.

  6. Optional. If your application uses a SQL Server Database connection string, then the string can be edited here to change the server name, username, password.
  7. Click Next.

    The package is deployed.


Monday, April 11, 2016

Create a simple C# Web Service API to insert a record into a SQL Server database

Creating a Web Service API in C# that talks to a SQL Server database in Visual Studio is relatively straightforward. It comes with a number of wizards that guide through the process. First, create a project by

  1. Start Visual Studio. Select New Project. Choose Templates | Visual C# | Windows | Web. Choose ASP.NET Web Application.

    The New Project dialog box appears.

  2. Type in a new Name, Solution Name and/or Browse to a new Location. Click OK

    The project is created.
  3. In the Solution Explorer pane on the right, double click on the file Web.config.

    The editor shows the contents of Web.config.
  4. Add in a new section for connectionString, as shown in the screenshot below.

    Note: obviously, the connection string values will vary depending on the server name, database, and user name, so they need to be changed accordingly
    .


  5. In the Solution Explorer pane, right click on the Controllers folder node and choose Add Controller.

    The Add Scaffold dialog box appears.

  6. Select an appropriate controller e.g. Web API 2 Controller with read/write action. Click Add. Type in the new Controller name, e.g. LogController. Click Add.


    A skeleton controller is created.
  7. Open the newly created file e.g. LogController.cs in the editor. Type in a method e.g. Get. An example is shown below. 
Note: in this example, when a user calls the address in a browser with the Route pattern http://some.server.com/api/log/[some latitude number]/[some longitude number], the second Get method is called. If the call is successful, the latitude and longitude values would have been inserted into the SQL Server database.
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data.SqlClient;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace ProductsAPP.Controllers
{
    public class LogController : ApiController
    {
        // GET: api/Log
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }

        [Route("api/Log/{lat}/{lon}")]
        public string Get(double lat, double lon)
        {
            //Get the SQL Server database connection string from
            //the Web.config file
            ConnectionStringSettings settings;
            settings = System.Configuration.ConfigurationManager.ConnectionStrings["Database1Connection"];
            string connectionString = settings.ConnectionString;

            //Create a new SQL Server database connection
            SqlConnection conn;
            conn = new SqlConnection(connectionString);
            try
            {
                //Open a connection
                conn.Open();

                //Create a parameterized SQL command to insert
                string query =
                    "INSERT INTO point_datatable (latitude, longitude) ";
                query += " VALUES (@latitude, @longitude)";
                SqlCommand cmd = new SqlCommand(query, conn);
                cmd.Parameters.AddWithValue("@latitude", lat);
                cmd.Parameters.AddWithValue("@longitude", lon);

                //Run the insert statement
                cmd.ExecuteNonQuery();

                conn.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception:" + ex.Message);
            }
            return "ok";
        }
    }
}

Monday, April 4, 2016

Using EmguCV/OpenCV to correct optical distortions from photos

After calibrating a camera and obtaining the camera matrix and optical distortion coefficient matrix of the camera, the calculated matrices can be used to perform correction of photo images captured using the same camera. The open source libraries EmguCV and OpenCV have the methods and functions to undistort images given the parameters determined previously. The following snippets show how to perform the correction.

The following code C# snippet extends the EmguCV Mat class to enable us to get and set values in the matrix by row and column indices.
// Source: http://stackoverflow.com/questions/32255440/how-can-i-get-and-set-pixel-values-of-an-emgucv-mat-image
// Extends the EmguCV Mat class with Get and Set matrix values
    // by row and column indices
    public static class MatExtension
    {
        public static dynamic GetValue(this Mat mat, int row, int col)
        {
            var value = CreateElement(mat.Depth);
            Marshal.Copy(mat.DataPointer + (row * mat.Cols + col) * mat.ElementSize, value, 0, 1);
            return value[0];
        }

        public static void SetValue(this Mat mat, int row, int col, dynamic value)
        {
            var target = CreateElement(mat.Depth, value);
            Marshal.Copy(target, 0, mat.DataPointer + (row * mat.Cols + col) * mat.ElementSize, 1);
        }
        private static dynamic CreateElement(DepthType depthType, dynamic value)
        {
            var element = CreateElement(depthType);
            element[0] = value;
            return element;
        }

        private static dynamic CreateElement(DepthType depthType)
        {
            if (depthType == DepthType.Cv8S)
            {
                return new sbyte[1];
            }
            if (depthType == DepthType.Cv8U)
            {
                return new byte[1];
            }
            if (depthType == DepthType.Cv16S)
            {
                return new short[1];
            }
            if (depthType == DepthType.Cv16U)
            {
                return new ushort[1];
            }
            if (depthType == DepthType.Cv32S)
            {
                return new int[1];
            }
            if (depthType == DepthType.Cv32F)
            {
                return new float[1];
            }
            if (depthType == DepthType.Cv64F)
            {
                return new double[1];
            }
            return new float[1];
        }

The following code snippet is an example function that performs the correction to a list of JPEG images in a folder D:\Temp\.

public static void Undistort()
        {
            Mat cameraMatrix = new Mat(3, 3, DepthType.Cv64F, 1);
            Mat distCoeffs = new Mat(5, 1, DepthType.Cv64F, 1);
            Mat image = null;

            //Camera matrix values
            double fx = 3388.49;
            double fy = 3390.57;
            double cx = 2096.43;
            double cy = 1566.23;
            double skew = 1.11273;
            
            //Optical distortion coefficient values
            double k1 = 0.17352;
            double k2 = -0.484226;
            double k3 = 0.344761;
            double p1 = 0.00075256;
            double p2 = -0.000269617;

            //Set the camera matrix
            cameraMatrix.SetValue(0, 0, fx);
            cameraMatrix.SetValue(1, 1, fy);
            cameraMatrix.SetValue(0, 1, skew);
            cameraMatrix.SetValue(0, 2, cx);
            cameraMatrix.SetValue(1, 2, cy);
            cameraMatrix.SetValue(2, 2, 1);

            //Set the distortion matrix
            distCoeffs.SetValue(0, 0, k1);
            distCoeffs.SetValue(1, 0, k2);
            distCoeffs.SetValue(2, 0, p1);
            distCoeffs.SetValue(3, 0, p2);
            distCoeffs.SetValue(4, 0, k3);

            // get paths to image files
            string[] imageFiles = Directory.GetFiles(@"d:\temp\", "IMG_*.jpg");

            // for every image
            foreach (string imageFile in imageFiles)
            {
                // create new image object from file path.
                // append Und.jpg to the input filename for the output 
                string outFile = Path.Combine(Path.GetDirectoryName(imageFile), 
                    Path.GetFileNameWithoutExtension(imageFile) + "Und.jpg");

                Console.WriteLine("Processing {0}->{1}...", imageFile, outFile);
                
                //Read the input image
                image = CvInvoke.Imread(imageFile, LoadImageType.AnyColor);

                //Correct the input image
                Mat outFrame = image.Clone();
                CvInvoke.Undistort(image, outFrame, cameraMatrix, distCoeffs);
                
                //save the corrected image
                image = outFrame.Clone();
                image.Save(outFile);
                image.Dispose();
                outFrame.Dispose();
            }
        }

Monday, March 28, 2016

Using Agisoft Lens for calculating camera calibration and distortion coefficient matrices

OpenCV was giving me a hard time in calculating camera and optical distortion coefficient matrices from photo frame images of checker board pattern grids. So I tried alternative methods and I found the free Agisoft Lens (bundled with PhotoScan Professional and Standard versions) to be robust and easy to use.


  1. To determine the camera matrix and distortion coefficient matrix, run Agisoft Lens.


  2. Select Tools | Show Chessboard.

    A chessboard pattern is displayed on the screen.
  3. Use the camera you want to calibrate and take a few photos of the chessboard pattern at different angles. Then copy the images to the computer.
  4. In Agisoft Lens, select Tools | Add Photos.

    The Add Photos dialog box appears.
  5. Browse and select the chessboard images captured previously. Click Open.

    The images are listed in Agisoft Lens.

  6. Select Tools | Calibrate.

    The Calibration dialog box appears.

  7. Toggle on the camera and distortion coefficient parameters you want to calculate. Click OK.

    Processing messages appear.


    The matrices are calculated and displayed.

  8. Note down or save the parameters fx, fy, cx, cy, k1, k2, k3, p1, p2.

    Note: the focal length units are in pixels

Monday, March 21, 2016

Setup and Deployment (Installer) project for Visual Studio Community 2015

For a long time, Microsoft took out the Setup and Deployment project template from the free Visual Studio Express and Community editions. While you could code and develop Visual Studio projects, it was not possible to create an installer directly from within Visual Studio itself. You would have to use 3rd party solutions like Nullsoft's NSIS. So I was pleasantly surprised when I found an official Microsoft Visual Studio 2015 Installer extension that can be downloaded and installed to create installers from within Visual Studio Community.

The extension can be obtained by the following steps:

  1. In Visual Studio Community 2015, select Tools | Extensions and Updates.

    The Extensions and Updates dialog box appears.
  2.  In the left pane, select Online. Then in the Search text box, type in a search string e.g. Visual Studio Installer. Press RETURN.

    A list of extensions is displayed.
  3. Select the extension Microsoft Visual Studio 2015 Installer Project. Click Download.

    The file VSI_Bundle.exe is downloaded.
  4. Run the downloaded VSI_Bundle.exe file.

    The extension is installed.
From now on, a new Visual Studio Installer project can be created within Visual Studio 2015 Community, as shown below. 

Monday, March 14, 2016

Trainsity Sapporo App for Windows Phone

 With this Windows Phone 8+ app, find your way around the city of Sapporo, Japan using the high resolution vector maps of the Namboku, Tozai and Toho metro rail lines.

The maps have small file size footprints but with many levels of zoom and can work offline without connecting to the Internet. You can zoom closer without having the details becoming blurred or "pixelated", like bitmap images. Users can click the train station labels to open Bing Maps, where they can use all the functions of the Google app to visualize the surrounding area and/or perform routing for directions. There is also an offline function to calculate the best way to travel from a station to another station with a direction breakdown and estimated timings (which may vary from the actual travelling time).

The following screenshots show how the app looks like on a Windows Phone 8+ handset.
When a tile is tapped, a detail map view of the selected line will appear, as shown below.
tapping a labeled box on the map will display the train station on the external Maps application, as shown below.
If you want to find how long it takes to travel from one station to another station, and the best route to take, simply swipe to the Route page. Then type in the From station and To station. As you enter the values, a drop down list will appear and a station can be selected from the list. Finally tap the Execute icon.
Tapping the more details link will display the recommended route to take.
Click the button below to download the app from the Windows store.
Get it from Microsoft
Related Posts with Thumbnails