Monday, July 24, 2017

TORCS: Track and Segments

I came across fiddling with torcs for a while for self-driving tests. In some case, I need to reset the car to the middle of the track when stuck. After some trial and error and studying into the code, I found out that the tCar struct always records the closest main part of the track in trkPos, albeit the car might be in the rside and lside segments attached to the track. So generally, one section of a track consists of main road, left side and right side, left border and right border. Their composition is as follows,

Monday, June 13, 2016

Image Processing - Histogram Equalization - Part 2

Draw Histograms

# draw flattened histogram
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image
%matplotlib inline

im = Image.open("sample.jpg")
im_arr = np.array(im)
print im_arr.shape

plt.figure(figsize=(15,5))
plt.subplot(1,2,1)
plt.imshow(im_arr)
plt.axis('off')

plt.subplot(1,2,2)
im_r = im_arr[:,:,0].flatten() # 3d (r,g,b) to 1d (stacked)
im_g = im_arr[:,:,1].flatten()
im_b = im_arr[:,:,2].flatten()
imhist, bins = np.histogram(im_r, 256, normed=True) #bins are a sequence of data range
plt.plot(imhist, label="Red")
imhist, bins = np.histogram(im_g, 256, normed=True)
plt.plot(imhist, label="Green")
imhist, bins = np.histogram(im_b, 256, normed=True)
plt.plot(imhist, label="Blue")
plt.legend(loc=1)

Histogram Equalization on Grayscale Image

# histogram equalization
def histeq(im, nbr_bins=256):
    imhist,bins = np.histogram(im.flatten(),nbr_bins,normed=True)
    cdf = imhist.cumsum() # cumulative distribution function (cumulative sum)
    cdf = 255 * cdf / cdf[-1] # normalization (brilliant! cdf[-1] is the sum of all)
    im2 = np.interp(im.flatten(), bins[:-1], cdf) # (x', x, fx) linear interpolate x' accordingg to x -> f(x)
    return im2.reshape(im.shape), cdf

im_gray = np.array(im.convert('L')) # interpolate in grayscale
im2, cdf = histeq(im_gray) # increase the dark area

plt.figure(figsize=(15,10))
plt.subplot(2,2,1)
plt.imshow(im_gray,cmap='gray')

plt.subplot(2,2,2)
plt.imshow(im2,cmap='gray')

plt.subplot(2,2,3)
plt.plot(cdf, label="Cumulative Distribution Function")
plt.legend(loc=2)

imhist2, bins2 = np.histogram(im2, 256, normed=True)
plt.subplot(2,2,4)
plt.plot(imhist2, label="Equalized Historgram")
plt.legend(loc=1)

Histogram Equalization on Colored Image

im = Image.open("Luncheon.jpg")
im_arr = np.array(im)

img_r = im_arr[:,:,0]
img_g = im_arr[:,:,1]
img_b = im_arr[:,:,2]

im_r_eq, cdf = histeq(img_r)
im_g_eq, cdf = histeq(img_g)
im_b_eq, cdf = histeq(img_b)

im_eq = np.zeros(im_arr.shape, 'uint8')
print im_r_eq.shape
im_eq[:,:,0] = im_r_eq
im_eq[:,:,1] = im_g_eq
im_eq[:,:,2] = im_b_eq
print im_eq.shape

plt.figure(figsize=(15,10))
plt.subplot(2,3,1)
plt.imshow(im_r_eq, cmap="gray")
plt.axis('off')

plt.subplot(2,3,2)
plt.imshow(im_g_eq, cmap="gray")
plt.axis('off')

plt.subplot(2,3,3)
plt.imshow(im_b_eq, cmap="gray")
plt.axis('off')

ime = Image.fromarray(im_eq)
plt.subplot(2,3,4)
plt.imshow(ime)
plt.axis('off')

plt.subplot(2,3,5)
plt.imshow(im)
plt.axis('off')

Monday, June 6, 2016

Matplotlib: Image Processing - Part 1

Remapping Images

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

n_row, n_col = 1, 5
plt.figure(figsize=(n_col*3,n_row*3),dpi=100)

img = Image.open("sample.jpg")
plt.subplot(n_row, n_col, 1)
plt.imshow(img)
plt.axis('off')

# gray
img2 = np.array(img.convert('L'))
plt.subplot(n_row, n_col, 2)
plt.imshow(img2, cmap='gray')
plt.axis('off')

# inverse
img3 = 255 - img2
plt.subplot(n_row, n_col, 3)
plt.imshow(img3, cmap='gray')
plt.axis('off')

# map to 100 ... 200
img4 = (100.0/255)*img2 + 100
plt.subplot(n_row, n_col, 4)
plt.imshow(img4, cmap='gray')
plt.axis('off')

# squared
img5 = 255.0 * (img2/255.0) **2
plt.subplot(n_row, n_col, 5)
plt.imshow(img5, cmap='gray')
plt.axis('off')

Plot multiple functions together

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

f1 = np.array(range(255))
# f1 = np.linspace(0,255,255,endpoint=True)
f2 = 255 - f1
f3 = (100.0/255)*f1 + 100
f4 = 255.0*(f1/255.0)**2

plt.figure(figsize=(8,5))
plt.plot(f1,f1,label="f(x)=x")
plt.plot(f1,f2,label="f(x)=255-x")
plt.plot(f1,f3,label="f(x)=(100.0/255)*x + 100")
plt.plot(f1,f4,label="f(x)=255.0*(x/255.0)**2")
plt.axis([0,260, 0, 260])
plt.legend(loc=2)

print min(f1), max(f1)
print min(f2), max(f2)
print min(f3), max(f3)
print min(f4), max(f4)

Tuesday, March 11, 2014

XSLT: Structuring Data in Attributes or in Child Elements

We are free to select tags to our liking, so are to build an XML structure, whether it is element-based, where there is almost no attributes in the XML tree (see the following exmample) or attribute-based (converted by XSLT code to be shown below).

<?xml version="1.0" encoding="UTF-8"?>
<catalog>
 <cd>
  <title>Empire Burlesque</title>
  <artist>Bob Dylan</artist>
  <country>USA</country>
  <company>Columbia</company>
  <price>10.90</price>
  <year>1985</year>
 </cd>
 <cd>
  <title>Hide your heart</title>
  <artist>Bonnie Tyler</artist>
  <country>UK</country>
  <company>CBS Records</company>
  <price>9.90</price>
  <year>1988</year>
 </cd>
 <cd>
  <title>Greatest Hits</title>
  <artist>Dolly Parton</artist>
  <country>USA</country>
  <company>RCA</company>
  <price>9.90</price>
  <year>1982</year>
 </cd>
 <cd>
  <title>Still got the blues</title>
  <artist>Gary Moore</artist>
  <country>UK</country>
  <company>Virgin records</company>
  <price>10.20</price>
  <year>1990</year>
 </cd>
 <cd>
  <title>Eros</title>
  <artist>Eros Ramazzotti</artist>
  <country>EU</country>
  <company>BMG</company>
  <price>9.90</price>
  <year>1997</year>
 </cd>
 <cd>
  <title>One night only</title>
  <artist>Bee Gees</artist>
  <country>UK</country>
  <company>Polydor</company>
  <price>10.90</price>
  <year>1998</year>
 </cd>
 <cd>
  <title>Sylvias Mother</title>
  <artist>Dr.Hook</artist>
  <country>UK</country>
  <company>CBS</company>
  <price>8.10</price>
  <year>1973</year>
 </cd>
 <cd>
  <title>Maggie May</title>
  <artist>Rod Stewart</artist>
  <country>UK</country>
  <company>Pickwick</company>
  <price>8.50</price>
  <year>1990</year>
 </cd>
 <cd>
  <title>Romanza</title>
  <artist>Andrea Bocelli</artist>
  <country>EU</country>
  <company>Polydor</company>
  <price>10.80</price>
  <year>1996</year>
 </cd>
 <cd>
  <title>When a man loves a woman</title>
  <artist>Percy Sledge</artist>
  <country>USA</country>
  <company>Atlantic</company>
  <price>8.70</price>
  <year>1987</year>
 </cd>
 <cd>
  <title>Black angel</title>
  <artist>Savage Rose</artist>
  <country>EU</country>
  <company>Mega</company>
  <price>10.90</price>
  <year>1995</year>
 </cd>
 <cd>
  <title>1999 Grammy Nominees</title>
  <artist>Many</artist>
  <country>USA</country>
  <company>Grammy</company>
  <price>10.20</price>
  <year>1999</year>
 </cd>
 <cd>
  <title>For the good times</title>
  <artist>Kenny Rogers</artist>
  <country>UK</country>
  <company>Mucik Master</company>
  <price>8.70</price>
  <year>1995</year>
 </cd>
 <cd>
  <title>Big Willie style</title>
  <artist>Will Smith</artist>
  <country>USA</country>
  <company>Columbia</company>
  <price>9.90</price>
  <year>1997</year>
 </cd>
 <cd>
  <title>Tupelo Honey</title>
  <artist>Van Morrison</artist>
  <country>UK</country>
  <company>Polydor</company>
  <price>8.20</price>
  <year>1971</year>
 </cd>
 <cd>
  <title>Soulsville</title>
  <artist>Jorn Hoel</artist>
  <country>Norway</country>
  <company>WEA</company>
  <price>7.90</price>
  <year>1996</year>
 </cd>
 <cd>
  <title>The very best of</title>
  <artist>Cat Stevens</artist>
  <country>UK</country>
  <company>Island</company>
  <price>8.90</price>
  <year>1990</year>
 </cd>
 <cd>
  <title>Stop</title>
  <artist>Sam Brown</artist>
  <country>UK</country>
  <company>A and M</company>
  <price>8.90</price>
  <year>1988</year>
 </cd>
 <cd>
  <title>Bridge of Spies</title>
  <artist>T`Pau</artist>
  <country>UK</country>
  <company>Siren</company>
  <price>7.90</price>
  <year>1987</year>
 </cd>
 <cd>
  <title>Private Dancer</title>
  <artist>Tina Turner</artist>
  <country>UK</country>
  <company>Capitol</company>
  <price>8.90</price>
  <year>1983</year>
 </cd>
 <cd>
  <title>Midt om natten</title>
  <artist>Kim Larsen</artist>
  <country>EU</country>
  <company>Medley</company>
  <price>7.80</price>
  <year>1983</year>
 </cd>
 <cd>
  <title>Pavarotti Gala Concert</title>
  <artist>Luciano Pavarotti</artist>
  <country>UK</country>
  <company>DECCA</company>
  <price>9.90</price>
  <year>1991</year>
 </cd>
 <cd>
  <title>The dock of the bay</title>
  <artist>Otis Redding</artist>
  <country>USA</country>
  <company>Atlantic</company>
  <price>7.90</price>
  <year>1987</year>
 </cd>
 <cd>
  <title>Picture book</title>
  <artist>Simply Red</artist>
  <country>EU</country>
  <company>Elektra</company>
  <price>7.20</price>
  <year>1985</year>
 </cd>
 <cd>
  <title>Red</title>
  <artist>The Communards</artist>
  <country>UK</country>
  <company>London</company>
  <price>7.80</price>
  <year>1987</year>
 </cd>
 <cd>
  <title>Unchain my heart</title>
  <artist>Joe Cocker</artist>
  <country>USA</country>
  <company>EMI</company>
  <price>8.20</price>
  <year>1987</year>
 </cd>
</catalog>

With the help of XSLT, we can easily transform element-based data into attribute-based data. Several points to notice in the XSLT code:

  • child selector child::
  • element name name()
  • element text text()
  • dynamic attribute name {name()}
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <catalog>
        <xsl:for-each select="catalog/cd">
            <cd>
                <xsl:for-each select="child::*">
                    <xsl:attribute name="{name(.)}">
                        <xsl:value-of select="text()"/>
                    </xsl:attribute>
                </xsl:for-each>
            </cd>
        </xsl:for-each>
        </catalog>
    </xsl:template>
</xsl:stylesheet>

Result: the attribute-based data.

<catalog>
    <cd title="Empire Burlesque" artist="Bob Dylan" country="USA" company="Columbia" price="10.90" year="1985" />
    <cd title="Hide your heart" artist="Bonnie Tyler" country="UK" company="CBS Records" price="9.90" year="1988" />
    <cd title="Greatest Hits" artist="Dolly Parton" country="USA" company="RCA" price="9.90" year="1982" />
    <cd title="Still got the blues" artist="Gary Moore" country="UK" company="Virgin records" price="10.20" year="1990" />
    <cd title="Eros" artist="Eros Ramazzotti" country="EU" company="BMG" price="9.90" year="1997" />
    <cd title="One night only" artist="Bee Gees" country="UK" company="Polydor" price="10.90" year="1998" />
    <cd title="Sylvias Mother" artist="Dr.Hook" country="UK" company="CBS" price="8.10" year="1973" />
    <cd title="Maggie May" artist="Rod Stewart" country="UK" company="Pickwick" price="8.50" year="1990" />
    <cd title="Romanza" artist="Andrea Bocelli" country="EU" company="Polydor" price="10.80" year="1996" />
    <cd title="When a man loves a woman" artist="Percy Sledge" country="USA" company="Atlantic" price="8.70" year="1987" />
    <cd title="Black angel" artist="Savage Rose" country="EU" company="Mega" price="10.90" year="1995" />
    <cd title="1999 Grammy Nominees" artist="Many" country="USA" company="Grammy" price="10.20" year="1999" />
    <cd title="For the good times" artist="Kenny Rogers" country="UK" company="Mucik Master" price="8.70" year="1995" />
    <cd title="Big Willie style" artist="Will Smith" country="USA" company="Columbia" price="9.90" year="1997" />
    <cd title="Tupelo Honey" artist="Van Morrison" country="UK" company="Polydor" price="8.20" year="1971" />
    <cd title="Soulsville" artist="Jorn Hoel" country="Norway" company="WEA" price="7.90" year="1996" />
    <cd title="The very best of" artist="Cat Stevens" country="UK" company="Island" price="8.90" year="1990" />
    <cd title="Stop" artist="Sam Brown" country="UK" company="A and M" price="8.90" year="1988" />
    <cd title="Bridge of Spies" artist="T`Pau" country="UK" company="Siren" price="7.90" year="1987" />
    <cd title="Private Dancer" artist="Tina Turner" country="UK" company="Capitol" price="8.90" year="1983" />
    <cd title="Midt om natten" artist="Kim Larsen" country="EU" company="Medley" price="7.80" year="1983" />
    <cd title="Pavarotti Gala Concert" artist="Luciano Pavarotti" country="UK" company="DECCA" price="9.90" year="1991" />
    <cd title="The dock of the bay" artist="Otis Redding" country="USA" company="Atlantic" price="7.90" year="1987" />
    <cd title="Picture book" artist="Simply Red" country="EU" company="Elektra" price="7.20" year="1985" />
    <cd title="Red" artist="The Communards" country="UK" company="London" price="7.80" year="1987" />
    <cd title="Unchain my heart" artist="Joe Cocker" country="USA" company="EMI" price="8.20" year="1987" />
</catalog>

Friday, March 7, 2014

VBScript: Dynamically Create GUIDs

Function CreateGUID()
 Set TypeLib = CreateObject("Scriptlet.TypeLib") 
 myGuid = CStr(TypeLib.Guid)
 CreateGUID = Left(myGuid, Len(myGuid)-2)
 Set TypeLib = Nothing
End Function

Wednesday, February 12, 2014

Windows Installer: Migrating From InstallShield to WiX

Notice: I've prepared my scripts into this repository github: IS2WiX [5].

Preparation

Installing WiX Toolset will get you all the tools to compile all XML files in your WiX project. It will also install templates to Visual Studio and VS does automatically configure compilation options for you.

We need programming knowledge from XSLT/XPATH to operate on XML files, also some VB.NET knowledge to write customized custom actions.

Here is a list of all related tools and languages.

  • WiX Toolset[1], documentation
  • Visual Studio 2012
  • Microsoft SDK (Orca.exe, Wilogutl.exe etc.[2])
  • XSLT, XPath, XML
  • VB.NET Custom Actions
  • InstallShield, Help file
  • Your InstallShield project file and Internet Explorer[3]

The Idea

WiX and InstallShield are tools to make .msi packages, they all base on Microsoft Windows Installer technology. They all use .xml files to represent their project, where .xml is either handcrafted or auto-generated from parameters set from a graphic interface. So to build a bridge between the two, we seek XSLT for help.

Example

Your Binary table shall look similar to this.
<table name="Binary">
 <col key="yes" def="s72">Name</col>
 <col def="V0">Data</col>
 <col def="S255">ISBuildSourcePath</col>
 <row><td>ISLockPermissions.dll</td><td/><td>[ISProductFolder]\redist\Language Independent\i386\ISLockPermissions.dll</td></row>
 <row><td>ISSCHRPL.DLL</td><td/><td>[ISProductFolder]\redist\language independent\i386\isschrpl.dll</td></row>
 <row><td>ISSetup.dll</td><td/><td>[ISProductFolder]\redist\language independent\i386\ISSetup.dll</td></row>
 ...
</table>

Let's write a stylesheet to convert the above table to WiX format,

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" />
    <xsl:template match="/">
        <xsl:for-each select="/table/row">
            <Binary>
                <xsl:attribute name="Id">
                  <xsl:value-of select="td[1]" /></xsl:attribute>
                <xsl:attribute name="SourceFile">
                  <xsl:value-of select="td[3]" /></xsl:attribute>
            </Binary>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

The output shall look like,

<Binary Id="ISLockPermissions.dll" SourceFile="[ISProductFolder]\redist\Language Independent\i386\ISLockPermissions.dll" />
<Binary Id="ISSCHRPL.DLL" SourceFile="[ISProductFolder]\redist\language independent\i386\isschrpl.dll" />
<Binary Id="ISSetup.dll" SourceFile="[ISProductFolder]\redist\language independent\i386\ISSetup.dll" />

View the InstallShield Project

Your project is composed of tables. With the help of stylesheet written in is.xsl[4], you could have a direct view of all these tables.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?xml-stylesheet type="text/xsl" href="is.xsl" ?>

From InstallShiled MSI tables to WiX

One can search help files provided by WiX to study how it is really mapped. The following is an incomplete list collected while I was working on a migration project.

IS/MSIWiX ElementParent
ActionTextProgressTextUI
AdminExecuteSequenceAdminExecuteSequenceFragment
AdminUISequenceAdminUISequenceFragment
AdvtExecuteSequenceAdvertiseExecuteSequenceProduct
AppSearchDirectorySearchProperty
BinaryBinaryFragment
CheckBoxControl Type="CheckBox" CheckBoxValue=""Dialog
ComponentComponentFragment, Directory
ControlControlDialog
ControlConditionConditionControl
ControlEventPublishUI
CreateFolderCreateFolderDirectory
CustomActionCustomActionFragment
DialogDialogUI
DirectoryDirectoryDirectoryref, Fragment
DrLocatorDirectorySearchProperty
ErrorErrorUI
EventMappingSubscribeControl
FeatureFeatureFeatureGroup, Fragment
FeatureComponentsFeatureRef, ComponentRef, ComponentGroupRefFragment
FileFileComponent
FontFile TrueType=yesComponent
ISStringStringWixLocalization
IconIconShortcut
InstallExecuteSequenceInstallExecuteSequenceProduct
InstallUISequenceInstallUISequenceUI
PropertyPropertyProduct
RadioButtonRadioButton, RadioButtonGroupControl
RegistryRegistryComponent
ServiceControlServiceControlComponent
ServiceInstallServiceInstallComponent
ShortcutShortcutComponent
TextStyleTextStyleUI
UITextUITextUI
UpgradeUpgrade, UpgradeVersionProduct

Footnote

  1. WiX Toolset
  2. Windows Installer Development Tools
  3. Chrome will have problems viewing an .xml file referencing another .xsl file locally due to the cross-origin security issue.
  4. By default, the stylesheet file should be at C:\Program Files (x86)\InstallShield\2011\Support\is.xsl
  5. Github: IS2WiX

Myriad

Visitors