- 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.
- Wait for the light bulb to appear, then either click on it or press ALT+ENTER.
A context menu appears. - Chose Extract String Resource.
The Extract Resource dialog appears. - 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. - Press OK.
The text in the layout is extracted into the selected string resource XML file.
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.
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.
- In Visual Studio's Solution Explorer pane, right click on the Web Service API project e.g. ProductsAPP.
- 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. - In the Target list, choose Custom. Click Next.
The New Custom Profile prompt appears. - Type in a profile name, e.g. ProductsAppProfile. Click OK.
- 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\.
- Optional: Type in a Site name e.g. ProductsApp. Click Next.
- Click Publish.
The package zip file is created.
- On the web server, start the Internet Information Services (IIS) Manager by clicking Start | Control Panel | Administrative Tools | Internet Information Services (IIS) Manager.
- In the Connection pane, expand the node.
- 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. - In the Connection pane, select a web site node e.g. Default web site.
- 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. - 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.
- 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
- Start Visual Studio. Select New Project. Choose Templates | Visual C# | Windows | Web. Choose ASP.NET Web Application.
The New Project dialog box appears. - Type in a new Name, Solution Name and/or Browse to a new Location. Click OK
The project is created. - In the Solution Explorer pane on the right, double click on the file Web.config.
The editor shows the contents of Web.config. - 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. - In the Solution Explorer pane, right click on the Controllers folder node and choose Add Controller.
The Add Scaffold dialog box appears. - 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. - Open the newly created file e.g. LogController.cs in the editor. Type in a method e.g. Get. An example is shown below.
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.
The following code snippet is an example function that performs the correction to a list of JPEG images in a folder D:\Temp\.
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(); } }