Category: Scripting

More Deskewing Rectangles with OpenCV

Someone recently posted to a mailing list that I read, asking for a program that can rotate and crop a lighter-colored rectangle on a black background. Since this fits in with the program I’m working on to locate, rotate, and deskew an image of a card in a photo, I figured I’d give it a shot. I’m planning to do both rotation and deskewing, but for now I’m only doing the rotation.

I’ve installed the latest OpenCV (version 2.3, as of this writing), and started learning the new Python bindings.  There seem to be a lot of cases where functions want a numpy array as an argument, but the functions don’t return numpy arrays, so there is a lot of fiddling around with the results of functions to get something that can be passed to another function.

On top of that, the return values of functions are poorly or rarely documented. Python’s duck-typing can help out a little in these cases, but if you call cv2.minAreaRect, you get something like ((233, 432), (565, 420), -0.2343), which is described in the documentation with the single word “retval”.  It would be helpful to have a way to find out that the first tuple is the center, the second is the width and height, and the third is the tilt (in degrees) of the “first” edge off of horizontal. That tuple makes just as much sense, but is wrong, when interpreted as the top left and bottom right corners and a tilt measured in radians.

Also, the “first” edge is seemingly arbitrary, or at least I can’t find any documentation describing it. This means that the same rectangle could be off by 0.4 degrees or by -89.6 degrees, depending on if the first edge is a horizontal or vertical edge. One thing that may be helpful is this stackoverflow post. Since the rectangle is defined as points, I can reshuffle the points to get them in a consistent order, and then get the angle off of horizontal for a consistent edge. That then goes into producing the transformation matrix for affine transforms (e.g. rotation and deskewing).

The minAreaRect() call gets me the angle I can use to rotate the image, and this trick should get me the four corners of the perspective-skewed image that can be straightened out to get the squared image.

Displaying contours in OpenCV

Suppose you have used FindContours to find the outlines of things in an image, and now want to color each one a different color, perhaps in order to create a seed map for the watershed algorithm. This gets you an image with each area that FindContours found in a different color:

#Showing the contours.
#contour_list is the output of cv.FindContours(), degapped is the image contours were found in
contour_img = cv.CreateImage(cv.GetSize(degapped), IPL_DEPTH_8U, 3)
contour = contour_list
while contour.h_next() != None:
    color = get_rand_rgb(80,255)
    holecolor = get_rand_rgb(80,255)
    cv.DrawContours(contour_img, contour, color, holecolor, -1, CV_FILLED)
    contour = contour.h_next()
show_img(contour_img, "contours " + str(iteration))

The real key here is iterating over the list of contours using h_next(), which took me longer than it should have to find.

The show_img() function is effectively just printf for OpenCV images, and looks like this:

def show_img(img, winName):
    #Debugging printf for images!
    cv.NamedWindow(winName)
    cv.ShowImage(winName, img)
    cv.WaitKey(0)
    cv.DestroyWindow(winName)

The function get_rand_rgb() gets a random RGB color with values for each color set to an integer in the range you pass it, like so:

def get_rand_rgb(min, max):
    return (random.randint(min,max),random.randint(min,max),random.randint(min,max))

I used 80,255 to get bright colors.

Magic Card Code

Now available at my GitHub repo. Note that using these scripts is probably a horrible violation of Wizards of the Coast’s ToS for their website, and can probably get you banned.

Gstreamer and the Logitech Pro 9000

This is a gstreamer pipeline that takes frames from a UVC camera on /dev/video0 and displays them on the screen, while simultaneously saving one frame per second to a file. In other words, it’s a single-command-line surveillance camera.

gst-launch v4l2src device=/dev/video0 ! ffmpegcolorspace ! video/x-raw-rgb,width=640,height=480 ! identity name=artoolkit ! tee name="logger" ! queue ! ximagesink sync=false logger. ! queue ! videorate ! video/x-raw-rgb,framerate=1/1 ! ffmpegcolorspace! pngenc snapshot=false ! multifilesink location="frame%05d.png"

Obviously, the camera can be set up to display in different resolutions, and save to differently named files. The next one expands the length of the section of the filename that changes to 8 digits, enough for one picture every second for 3.16 years. I also reorganized the order of the parameters so that ARToolkit can work with the data stream and do augmented reality stuff to it.

export ARTOOLKIT_CONFIG="v4l2src device=/dev/video0 ! tee name=logger ! queue ! ffmpegcolorspace ! video/x-raw-rgb,width=640,height=480 ! identity name=artoolkit ! fakesink sync=false logger. ! queue ! videorate ! video/x-raw-rgb,framerate=1/1 ! ffmpegcolorspace ! pngenc snapshot=false ! multifilesink location=frame%08d.png"

Conversation Initiation

A friend of mine said that she felt that she started AIM conversations more than other people started them with her. This made me curious about my AIM use at work, and whether I start more than half of my conversations. Fortunately, I keep logs and have useful tools for log analysis. I googled up some sed oneliners and spent a couple of minutes slapping shell scripts together to get this:

ams@temperance:~/.purple/logs$ find ./ -iname *.html | wc -l
365
ams@temperance:~/.purple/logs$ for file in `find ./ -iname *.html`; do sed -n 2p $file | grep ">AIM_handle|>GChat_handle" ; done | wc -l
72

The first command line finds all the files in my log file directory that are .html logs and counts the number of them with wc -l. This is how many conversations I have had. Before I ran that command, I deleted all the automated messages from AOL about being logged in in two places, which reduced the count by about 200.

The second command line finds all the files where the second line of the file (after the header) includes either my AOL handle or my GChat handle. That would indicate that the first message of the chat was a message from me, rather than anyone else.

These scripts are not great, as the files may have a second line that isn’t the first sentence of the conversation, but a quick look over the output of ams@temperance:~/.purple/logs$ for file in `find ./ -iname *.html`; do sed -n 2p $file ; done shows no weird second lines.

According to the scripts, then, I start about one fifth of the conversations I have at work. On my home computer, I have 401 log files, and 101 of them are conversations I started, making the ratio closer to one forth. This makes sense, as I am more likely to start talking to people at home than at work.

It would also be interesting to graph which people I start conversations with more, and which ones start conversations with me.

Tags : , ,