Login [Register]
Don't have an account? Register now to chat, post, use our tools, and much more.
I recently picked up python again (I barely did anything last time >.> ), and I have decided on a project I want to do to A. work on my Python skills and B. be really awesome =P

The project I have chosen is basically a paintball sentry gun (although I will just start with a laserpointer) I saw the sentry gun that a person made on youtube and now I really want to try to make one myself >.>

the project is going to be incredibly advanced for me, but thank
I am doing relatively well with one portion of the project, I have been doing extensive research on the topic and finding as many examples as I can in Python (most are in c and c++ and use libraries with no python binding, but I think I finally found a good one - Opencv has python bindings). The harder part for me, however, is going to be the hardware.

Does anybody have any good suggestions on
1. good motors that could rotate a paintball gun or something of similar mass up and down and around, but also easily interfaced with a computer (I will probably end up having a friend of mine get me some motors and wiring it, because I suck with hardware)
2. a good tutorial on controlling motors in python (unfortunately the computer I am using does not have a serial port, but I am sure there are some usb->serial converters somewhere, my mom may actually have one)

it is possible this project will die, but it is something that I really want to try =)







CURRENT CODE: must have webcam, PyGame, Python Imaging Library and VideoCapture (google them)

I also recommend Psyco since it seems to yield a noticeable speed difference (although it may be just a phychological effect >.> )

If you do have Psyco, uncomment the last 2 lines of import (the ones with psyco in them =P )


After a lot of work I finally retried the flood fill method for blob detection, and it turns out the method I used before sucked >.>

The method now is completely iterative and it keeps up with my frame rate of 24 fps (the cpu usage IS 30%, but this would be the only thing running at any time >.> )

If you have not tried it yet, TRY IT NOW!


When running this code, SIT OUT OF THE WAY UNTIL YOU SEE A VIDEO FEED (this is so it can get the background etc. if you move out of the way afterwards, it will redo the background after a couple seconds, I have the refresh set to 50 loops of the number of targets being the same, it does not have to be consecutive)

try throwing a small object into the scene, or running in and taking something out, or moving it slightly, just to see how sensitive it is =)




Code:
#http://www.codeproject.com/KB/audio-video/Motion_Detection.aspx
#http://www.pythonware.com/library/pil/handbook/image.htm#image-mode-attribute
#take stream from webcam
#get initial frame
#subtract initial frame from subsequent frames
#check for differences
#draw rectangles around differences, rate by size
#########################################################
import Image, ImageChops, ImageFilter
import pygame
from pygame.locals import *
from VideoCapture import Device
import sys
import psyco
psyco.full()


REFRESH = 50

fps = 24
cam = Device(devnum=0)
#Device.displayCapturePinProperties(cam)
Device.displayCaptureFilterProperties(cam)


def get_image():
    return Device.getImage(cam, timestamp=0, boldfont=0, textpos='bl')

def flood((x,y), temparray,retlist):
       
        """takes in current x and y coordinated, and then iterates through
        temp array starting at x and y, trying to come back around to the beginning
       
        """
        temparray[x,y] = 0
        retlist.append([x,y])
        if temparray[x,y-1] == 255:
                flood((x,y-1), temparray,retlist)
        if temparray[x+1,y] == 255:
                flood((x+1,y), temparray,retlist)
        if temparray[x,y+1] == 255:
                flood((x,y+1), temparray,retlist)
        if temparray[x-1,y] == 255:
                flood((x-1,y), temparray,retlist)
        return retlist

def flood_fill(temparray):
        blist = []
        for yline in xrange(120):
                for xline in [0,159]:
                        temparray[xline,yline] = 0
        for yline in [0,119]:
                for xline in xrange(160):
                        temparray[xline,yline] = 0
        for yline in xrange(1,119):
                for xline in xrange(1,159):
                        if temparray[xline,yline] == 255:
                                retlist = []
                                tlist = flood((xline,yline),temparray,retlist)
                                xlist = []
                                ylist = []
                                for a in xrange(len(tlist)):
                                        xlist.append(tlist[a][0])
                                        ylist.append(tlist[a][1])
                                blist.append([min(xlist)*4,max(xlist)*4,min(ylist)*4,max(ylist)*4])
        return blist



pygame.init()
res = (640,480)
pygame.init()
screen = pygame.display.set_mode((800,480))
pygame.display.set_caption('Webcam')

def get_image():
    return Device.getImage(cam, timestamp=0, boldfont=0, textpos='bl')


lowpix = 35
backgroundframe = get_image()
backgroundframe = backgroundframe.resize((160,120))
backgroundframe = backgroundframe.convert("L",dither=Image.NONE)
averagex = 370
averagey = 240


blobs = 0
lblobs = 0
conblobs = 0
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT: sys.exit()
        keyinput = pygame.key.get_pressed()
        if keyinput[K_1]: fps += 1
        if keyinput[K_2]: fps -= 1
        if keyinput[K_3]: lowpix += 1
        if keyinput[K_4]: lowpix -= 1
        if keyinput[K_5]:
            backgroundframe = get_image()
            backgroundframe = backgroundframe.resize((160,120))
            backgroundframe = backgroundframe.convert("L",dither=Image.NONE)
        print fps
    dispimg = get_image()



   
    compimg = dispimg.resize((160,120)).convert("L",dither=Image.NONE)
    difframe = ImageChops.difference(backgroundframe, compimg)
    difframe = difframe.point(lambda p: (p>lowpix) * 255.0)
    difframe = difframe.filter(ImageFilter.ModeFilter)
    difframe = difframe.filter(ImageFilter.MaxFilter)
    difframe = difframe.filter(ImageFilter.MaxFilter)
    difframe = difframe.filter(ImageFilter.MaxFilter)
    pgimg2 = difframe.convert("RGB")

    if difframe.histogram()[255] < 10000:
        repdifframe = difframe
        tarray = repdifframe.load()
        bloblist = flood_fill(tarray)
        blobs = len(bloblist)
    else:
        backgroundframe = get_image()
        backgroundframe = backgroundframe.resize((160,120))
        backgroundframe = backgroundframe.convert("L",dither=Image.NONE)

   
    if blobs:
        print [lblobs,blobs,conblobs]
        if lblobs == blobs:
            conblobs += 1
        if conblobs > REFRESH: 
            backgroundframe = get_image()
            backgroundframe = backgroundframe.resize((160,120))
            backgroundframe = backgroundframe.convert("L",dither=Image.NONE)
            conblobs = 0
        if blobs == 0:
            conblobs = 0
        lblobs = blobs
       

   
    pgimg = pygame.image.frombuffer(dispimg.tostring(), res, "RGB")
    pgimg2 = pygame.image.frombuffer(pgimg2.tostring(), (160,120), "RGB")
    pgimg = pgimg.convert()
    pgimg2 = pgimg2.convert()
    screen.blit(pgimg, (0,0))
    screen.blit(pgimg2, (640,0))

    if len(bloblist)>0:
        for tlist in bloblist:
            averagex = (tlist[0]+tlist[1])/2
            averagey = (tlist[2]+tlist[3])/2
            pygame.draw.circle(screen, (255, 0, 0), (averagex, averagey), 10, 5)
            pygame.draw.line(screen, (255,0,0), (averagex,averagey-16), (averagex,averagey+16), 3)
            pygame.draw.line(screen, (255,0,0), (averagex-16,averagey), (averagex+16,averagey), 3)
            pygame.draw.rect(screen, (255,0,0),(tlist[0],tlist[2],tlist[1]-tlist[0],tlist[3]-tlist[2]), 3)


    pygame.display.flip()
    pygame.time.delay(int(1000 * 1.0/fps))



Why not email the guy who made the paintball sentry gun you saw on youtube, and ask what motors he used? (willysm38@comcast.net)
Pseudoprogrammer wrote:
Why not email the guy who made the paintball sentry gun you saw on youtube, and ask what motors he used.? (willysm38@comcast.net)


good idea, and done =D
Does the computer have a parallel port? If it does, this will be really, really easy. If it doesn't, you will need a microcontroller of some sorts (good list of pre-built ones here: http://dev.emcelettronica.com/microcontrollers-usb-stick-tool )

The motor you use can be any DC motor, it doesn't really matter (so long as it is powerful enough to rotate/move whatever you need).

Those USB->Parallel/Serial adapters do *NOT* work for this sort of thing!
Or you could use stepper motors for fine-grained control. Servos would be ok too, just more coarse control.
nope, no parallel port on my laptop =\

lol, I have a feeling this is going to be an expensive project (although I may be able to borrow a couple things from friends to test it out first etc.)

I think I will not worry about hardware right now, it is probably better to just get the software portion of the motion tracking etc. done, and then worry about the rest of it. I am going to look at the microcontrollers now however.

What would you recommend for general economy and quality (it looks like most of them are in the 40-50 dollar range) For me, http://www.silabs.com/tgwWebApp/public/web_content/products/Microcontrollers/en/USBToolStick.htm or http://focus.ti.com/docs/toolsw/folders/print/ez430-f2013.html seems to be a nice price =)
Harq wrote:
nope, no serial port on my laptop =\


No goddammit, stop and read, ok? PARALLEL PORT. Do you have a PARALLEL PORT?.

No one gives a shit about serial ports, they are worthless.
Kllrnohj wrote:
Harq wrote:
nope, no serial port on my laptop =\


No goddammit, stop and read, ok? PARALLEL PORT. Do you have a PARALLEL PORT?.

No one gives a <font color=red>censored</font> about serial ports, they are worthless.


I meant parallel >.> All I have are usb, dvi, and vga (and a pcmcia, but pcmcia -> parallel are expensive)
Kllrnohj wrote:
Harq wrote:
nope, no serial port on my laptop =\


No goddammit, stop and read, ok? PARALLEL PORT. Do you have a PARALLEL PORT?.

No one gives a <font color=red>censored</font> about serial ports, they are worthless.
Not worthless at all, with a $0.50 shift register you can get a parallel port out of one.
KermMartian wrote:
Not worthless at all, with a $0.50 shift register you can get a parallel port out of one.


Still worthless. USB > Serial (and is almost as cheap). If you have to program for serial (on the PC side), its easier to do USB than serial as there are modern libraries for USB (libusb comes to mind). On the hardware side the two are going to be pretty close, except there are many micro controllers out their with a built in USB controller so you don't even need to muck with the serial communications.

Hence, serial is worthless Razz
So I wrote my own blob finder (it is basically composed of an edge tracer that follows the outline and returns the size of the outline, and a loop)

I have it working relatively well, but now I need to fix the loop (I tested it at a specific entry point of a picture instead of how it will usually be, which is scanning from top to bottom).

for some really wierd reason, the code is throwing wierd errors at the loop (I had this problem with a different section earlier too, but I do not know how I solved it)

File "C:\Users\David\Desktop\python\turret\motiondet blob experiment.py", line 83, in <module>
for cury in xrange[480]:
TypeError: 'type' object is unsubscriptable


The code in question is this:

Code:

    for cury in xrange[480]:
        for curx in xrange[640]:
            if tarray[curx,cury] == 255:
                edgelist = (bigcolor.edge_finder(240,240, tarray))
                print len(edgelist)
                if len(edgelist) > 100:
                    averagex = 0
                    averagey = 0
                for value in edgelist:
                    averagex = averagex + value[0]
                    averagey = averagey + value[1]
                tdifframe = ImageDraw.Draw(difframe)
                averagex = averagex / len(edgelist)
                averagey = averagey / len(edgelist)
                tdifframe.arc([averagex,averagey,averagex+10,averagey+10],0,360,(255,0,0))
                del tdifframe


any ideas here? this is the first time that variable is used and I have no idea why it is doing this =\
Dude, xrange is a FUNCTION. You can't do an array index on a function Razz

Hell, that code you wrote doesn't work/make sense in *any* language...
Kllrnohj wrote:
Dude, xrange is a FUNCTION. You can't do an array index on a function Razz

Hell, that code you wrote doesn't work/make sense in *any* language...


well that explains it >.>
I probably did that because I was spending so much time trying to figure our how PIL passed image arrays (turns out it is much easier if I pass it after it is converted to black and white >.>)

well I have implemented the blob finding in basically 3 different ways and they all suck >.> (wall following 2 different ways, and flood filling)

so it looks like I am going to implement a growing region algorithm to find the blobs >.> (it will be easier since everything is either black or white though =) )

I am pretty sure this is the way it works:
[it is from the comment I made to remind myself in my code =P
I am working on it and I have no idea if it will work or not, but I hope it will >.>

#http://geekblog.nl/entry/24
#go through line
#number each pixel(that is surrounded by at least 1 pixel)
#pixels on the line right next to each other have same number
#proceed to next line
#merge nearby pixels from previous line and also this line
#by giving them the same id number
#store this to array
#after you have gone through, go through again
#add each pixel to it's respective id list
#this includes adding the x,y coordinates so they may be averaged
#
#order to check
#each lineblob checks upwards and to its right
#possibly another pass to merge intersecting blobs together
#
Ok, blob detection will not run well at ALL in python >.>

For now I am going to take the easy way out and average the difference pixels together, it will be so much nicer for now =P

the main reason is that although there is a python binding for opencv, there is no documentation at ALL >.>

This is just for now though, I may be able to either find a library with good bindings, or I may be able to eventually write one in C or C++ =)
What are you talking about? There are tutorials and documentation here: http://opencvlibrary.sourceforge.net/Welcome
with the python differences noted here: http://opencvlibrary.sourceforge.net/PythonInterface

Also, have you tried using "help()" in an interactive session? The documentation is probably built in. You can also browse that help using the pydoc server (<Python directory>\Scripts\pydocgui.pyw)
Kllrnohj wrote:
What are you talking about? There are tutorials and documentation here: http://opencvlibrary.sourceforge.net/Welcome
with the python differences noted here: http://opencvlibrary.sourceforge.net/PythonInterface


please feel free to figure out hth to do blob tracking, there is almost no documentation at all for that part of the opencv library

I have code to convert IPL to PIL etc, so I could interface with it, but the documentation is kinda lacking in the tracking area...

although knowing more c++ would probably help me greatly (there are a lot of examples in c++, but the examples included for python are much more limited)
Harq wrote:
although knowing more c++ would probably help me greatly (there are a lot of examples in c++, but the examples included for python are much more limited)


You should be able to figure that out pretty easily. The function calls will be the same (they will just be in a package, which will follow a standard. For example, in wxWidgets a function will go from, say, wxLoad in C++ to wx.Load in python). You don't need to manage the type, so all that can be ignored.
I am not going to do that for now, but I probably will in the future. For now I redid both methods so they are much faster (try the first one, it is a lot more consistent and does not jump around)

they both only work with one target since they are just averaging the bounding box of movement (so the target would be in the middle of multiple people)

I also have both now do operations on a 160x120 image instead of 640x480 (so about 4 times faster) The sized down images are also run through some filters to remove the noise from almost imperceptible movements in the frame.
That should actually be a 21-fold decrease in calculation time, if you assume calculation time is linearly proportional t total number of pixels per frame.
No need for libraries =D

I made it myself, turns out the way I was doing floodfill before absolutely SUCKS

I changed it to be completely iterative and now it works without any slowdown at all (although because one of the blur filters does not work correctly, it often has a lot of little blobs)

If you have not tried this code out yet, try it! =D


By the way, Kllrnohj, wouldn't a usb -> serial converter specifically designed for robotics etc. work fine? Such as http://www.parallax.com/Store/Microcontrollers/BASICStampModules/tabid/134/ProductID/379/List/1/Default.aspx?SortField=ProductName,ProductName
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 2
» All times are GMT - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement