Ladies and Gentleman, turn your lights on
SourceCode
#!/usr/bin/python import pygame import pygame.camera class Capture(object): a = [] allines = [] found = 0 def __init__(self): self.size = (640,480) # create a display surface. standard pygame stuff self.display = pygame.display.set_mode(self.size, 0) # this is the same as what we saw before self.clist = pygame.camera.list_cameras() if not self.clist: raise ValueError("Sorry, no cameras detected.") self.cam = pygame.camera.Camera(self.clist[0], self.size) self.cam.start() # create a surface to capture to. for performance purposes # bit depth is the same as that of the display surface. self.snapshot = pygame.surface.Surface(self.size, 0, self.display) def get_and_flip(self): # if you don't want to tie the framerate to the camera, you can check # if the camera has an image ready. note that while this works # on most cameras, some will never return true. if self.cam.query_image(): self.snapshot = self.cam.get_image(self.snapshot) # blit it to the display surface. simple! self.display.blit(self.snapshot, (0,0)) pygame.display.flip() def main(self): going = True while going: for event in pygame.event.get() : if event.type == pygame.KEYDOWN : if event.key == pygame.K_SPACE : print "Space bar pressed down." elif event.key == pygame.K_ESCAPE : print "Escape key pressed down." elif event.type == pygame.KEYUP : if event.key == pygame.K_SPACE : del self.a[:] del self.allines[:] elif event.key == pygame.K_ESCAPE : pygame.quit() self.get_and_flip() def get_and_flip(self): self.snapshot = self.cam.get_image(self.snapshot) # threshold against the color we got before crect = pygame.draw.rect(self.display, (255,0,0), (145,105,30,30), 4) #self.ccolor = pygame.transform.average_color(self.snapshot, crect) mask = pygame.mask.from_threshold(self.snapshot, (240, 240, 255), (30, 30, 30)) self.display.blit(self.snapshot,(0,0)) # keep only the largest blob of that color connected = mask.connected_component() # make sure the blob is big enough that it isn't just noise if mask.count() > 100: # find the center of the blob coord = mask.centroid() self.a.append(coord) self.found = 0 else: self.found = self.found+1 #if we not found the threshold color more then 15 times #we create a new line if self.found > 15: self.allines.append(self.a[:]) del self.a[:] l = len(self.a) for i in range(len(self.allines)): if len(self.allines[i]) >1: pygame.draw.aalines(self.display, (255,255,255), 0, self.allines[i], 1) if l > 1: pygame.draw.aalines(self.display, (255,255,255), 0, self.a, 1) pygame.display.flip() pygame.init() pygame.camera.init() x = Capture() x.main()
Happy Hacking
Andreas
Ein guter Freund von mir war so freundlich, ein Python QT Interface zu meiner Website Thumbnailer API zu bauen.
Hier der Sourcecode:
from PyQt4.QtCore import * from PyQt4.QtGui import * from PyQt4.QtNetwork import * from designs.FetchDialog import Ui_FetchDialog import os,sys class MainClass(QDialog): def __init__(self, parent = None): super(QDialog, self).__init__() QApplication.setStyle(QStyleFactory.create('plastique')) self.layout = Ui_FetchDialog() self.layout.setupUi(self) self.layout.progress.hide() self.layout.btn_save.hide() self.layout.pic.hide() self.connect(self.layout.btn_save, SIGNAL("pressed()"), self.saveDownloadedImage) self.connect(self.layout.btn_get, SIGNAL("pressed()"), self.progressDownload) def progressDownload(self): self.layout.progress.setValue(0) self.layout.progress.show() self.networkmanager = QNetworkAccessManager(); request = QNetworkRequest() url = "http://codejungle.org/api/thumb_get.php?url=%s" % self.layout.url.text() request.setUrl(QUrl(url)) self.reply = self.networkmanager.get(request) self.connect(self.reply, SIGNAL("downloadProgress(qint64,qint64)"), self.updateProgressBar) self.connect(self.networkmanager, SIGNAL("finished(QNetworkReply *)"), self.showThumbnail) def showThumbnail(self, replyFromServer): if(replyFromServer.isFinished() == True): imageData = replyFromServer.readAll() if(imageData.size() == None): print "Error while reading image!" pixmap = QPixmap() pixmap.loadFromData(imageData) self.originalPixmap = pixmap if(pixmap.width() > 800): pixmap = pixmap.scaledToWidth(800) self.layout.pic.setPixmap(pixmap) self.layout.pic.setMaximumHeight(600) self.layout.pic.setMaximumWidth(800) self.layout.pic.show() self.layout.btn_save.show() replyFromServer.deleteLater() def saveDownloadedImage(self): saveTo = QFileDialog.getSaveFileNameAndFilter(parent=None, caption=QString(), directory = QString(), filter = "Images (*.png)") if(self.originalPixmap.save(saveTo[0], "png")): QMessageBox.information(self, "Success!", "Your image is now saved!") self.layout.pic.hide() self.layout.btn_save.hide() self.resize(530, 132) def updateProgressBar(self, bytesRecieved, bytesTotal): self.layout.progress.setMaximum(bytesTotal) self.layout.progress.setValue(bytesRecieved) if(self.layout.progress.value() == bytesTotal): self.layout.progress.hide() if __name__ == "__main__": app = QApplication([]) software = MainClass() software.show() app.exec_()
Known Bugs:
Vielen Dank an Mario (www.unite-it.at) an dieser Stelle.
Andreas
Ich habe in einem Artikel von der Möglichkeit geschrieben mit
MySQL-Proxy eine lastenverteilte Datenbank aufzubauen.
Heute möchte ich jedoch eine andere Alternative vorstellen.
Ich habe zu diesem Zweck eine Datenbank Lastenverteilungsklasse geschrieben.
Sie stellt drei Methoden zur Lastenverteilung bereit:
Simple Load Balancing verteilt die Last völlig willkürlich:
Vorteil: relativ schnell
Nachteil: Server können einseitig belastet werden
Load Balancing by Weight verteilt die Last nach Gewichtung:
Hat man z.B. eine starke und zwei schwache Maschinen
ist es möglich der starken mehr Gewichtung zu geben.
Nachteil: Der richtige Gewichtungswert von Maschinen ist schwer zu ermittelen
und kann sich im regulären Betrieb unerwartet ändern.
Load Balancing by Load verteilt die Last nach Systemauslastung:
Vorteil: Die Last wird an den Server verteilt, der am wenigsten zu tun hat.
Nachteil: Die zusätzliche Zeit, die benötigt wird, um die Systemlast der Server abzufragen.
Läuft nur unter Linux, benötigt memcache.
Derzeit wird die Systemlast 60 Sekunden im memcache zwischengespeichert um unnötige Anfragen
an den Webserver zu sparen,
evtl. muss dieser Wert angepasst werden, damit unter hoher Last die Maschinen nicht einseitig
belastet werden.
Desweiteren stellt die Klasse eine Methode zum Abfragen der durchschnittlichen Systemlast bereit
und ausserdem eine Methode die endscheiden kann, ob eine Abfrage auf den Master oder Slave laufen soll.
Code
<?
/**
* DBLoadBalancing implements three different methods for LoadBalancing
* and one Method for Read / Write Splitting
*
* Simple Load Balancing - random dissision
* Load Balancing by Weight - dissision by weight
* Load Balancing by Load - dissision by load
*
* @todo benchmark and test bevore useing it on productive system
* @author Andreas Beder <office@codejungle.org>
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
*/
class DBLoadBalancing{
var $config =array();
function __construct() {
//Config for Simple Load Balanncing
$this->config['slaves']=array("10.0.0.1","10.0.0.2", "10.0.0.3");
/*
//Config for Load Balancing by Weight
$this->config['slaves']=array("10.0.0.1"=>2,"10.0.0.2"=>0, "10.0.0.3"=>1);
//Config for Load Balancing by Load
$this->config['slaves']=array(
"10.0.0.1"=>"http://slave1/getload.php",
"10.0.0.2"=>"http://slave2/getload.php",
"10.0.0.3"=>"http://slave3/getload.php"
);
$this->config['memcache']=array(
"localhost"=>"11211",
"slave2", "11211"
);
*/
}
/**
* This Method checks if a Query
* can be run on Master or Slaves
*
* @param string $sql
* @return boolen
*
* @author Andreas Beder <office@codejungle.org>
*/
function ModifingQuery($sql){
$sql=strtolower(substr($sql, 0, 6));
switch ($sql) {
//selects can be run on slaves, because it's not a modifiny query
case "select":
return false;
break;
//insert, update, delete, alter must be executed on master
case "default":
return true;
}
return true;
}
/**
* Simple Load Balanncing
* Just random Load Balancing
*
* @return string ip
*
* @author Andreas Beder <office@codejungle.org>
*/
function SimpleLoadBalanncing(){
$i=count($this->config['slaves'])-1;
$rand=rand(0, $i);
return $this->config['slaves'][$rand];
}
/**
* Load Balancing by Weight
*
* @return string ip
*
* @author Andreas Beder <office@codejungle.org>
*/
function LoadBalancingByWeight(){
$i=count($this->config['slaves']);
foreach($this->config['slaves'] as $server => $weight){
$rand=rand(1, $i);
$lb[$server]=$rand+$weight;
}
arsort($lb);
return key($lb);
}
/**
* LoadBalancingByLoad
*
* This method checks the load on n server.
* Cache the result for 60 sec (because we don't want to ask too many times)
* Finaly it returns the Server ip with the lowest load
*
* @return string ip
*
* @author Andreas Beder <office@codejungle.org>
*/
function LoadBalancingByLoad() {
$memcache = new Memcache;
foreach($this->config['memcache'] as $memcahe_server => $port){
$memcache->addServer($memcahe_server, $port);
}
foreach($this->config['slaves'] as $server => $checkloadurl){
if($memcache->get($server)){
$load[$server]=$memcache->get($server);
}
else
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $checkloadurl);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($curl);
$memcache->set($memcache, $server, $output, 0, 60);
$load[$server]=$output;
curl_close($curl);
}
}
asort($load);
return key($load);
}
/**
* Get Load simply returns the laod average
* from the last minute
*
* @return float load avg
*
* @author Andreas Beder <office@codejungle.org>
*/
function GetLoad(){
$load=sys_getloadavg();
return $load[0];
}
}
?>
Ich habe versucht die Methoden so generisch zu schreiben, dass man sie auch für andere
Lastenverteilung nutzen kann.
Es ist ebenso denkbar, gewisse Methoden zu kombinieren.
Ich hoffe euch hat mein kleiner Artikel zur Lastenverteilung gefallen,
über Feedback würd' ich mich wie immer sehr freuen.
Eine Warnung noch zum Schluss, bitte verwendet die Klasse nicht ohne gezieltes
Benchmarking und Testing im Produktivsystem.
LG
Andreas
Ich habe mir gedacht, nachdem ich ja sonst nix zu tun habe, ein paar
Tage lang eine bestehende Applikation so umzuschreiben, dass
sie auf mehreren Servern läuft.
Als Basis werde ich meinen Reminder Service verwenden.
Der erste Schritt um die Performance zu verbessern ist immer
die Analyse der bestehenden Applikation, dazu gehört auch das Profiling, um
Bottlenecks besser zu lokalisieren.
Um die Skalierbarkeit zu verbessern, werde ich
gewisse Teile ausgliedern, man nennt dies auch funktionale
Partitionierung.
Man könnte bei einem typischen Blog zum Beispiel anfangen,
Kommentare, Benutzer und Nachrichten jeweils auf eine eigene Datenbank auszulagern.
Weiters könnte man mit Hilfe eines Lastenverteilers und mehreren Webservern die
Last aufteilen.
In unserem Beispiel haben wir zwei Kernbereiche, erstens das Userinterface,
worüber der Benutzer Daten anlegen, verändern und löschen kann und
zweitens das Backend, welches die eingegebenen Daten verarbeitet.
Im Idealfall können wir am Ende das Front und Backend auf N Servern horizontal skalieren.
Das bedeutet, wir erhöhen nicht nur die Geschwindigkeit, sondern schaffen zusätzlich Redundanzen,
die eine gewisse Ausfallsicherheit garantieren.
Schauen wir uns das bestehende Backend mal an:
Code
<?
include("./config.php");
$connect=@mysql_connect("$db_host", "$db_user", "$db_pass")
or die("<li>Cant connect to: $db_host with user: $db_user</li>");
@mysql_select_db($db, $connect)or die("Cant select DB");
// hier wird jeder job aus der datenbank geholt,
// der den staus planned hat und in der vergangenheit liegt.
$sql="SELECT jid, job.rid, subject, description, email, reminder.interval,
reminder.remind_date, reminder.auth
FROM job, reminder
WHERE
status='planned' AND
planned<UNIX_TIMESTAMP() AND
reminder.rid=job.rid";
$result=mysql_query($sql);
while($row=mysql_fetch_array($result)){
$header = 'MIME-Version: 1.0' . "n";
$header .= 'Content-type: text/html; charset=iso-8859-1' . "n";
$header .= 'To: "'.$row['email'].'" <'.$row['email'].'>' . "n";
$header .= 'From: "Remind ME" <remind@codejungle.org>' . "n";
$msg='
<html>
<head>
<title>RemindME</title>
</head>
<body>
'.$row['description'].'
<br/><hr><a href="http://www.codejungle.org/reminder/uid/'.$row[auth].'">Modify your Reminder</a>
</body>
</html>
';
if(mail($row['email'], $row['subject'], $msg, $header)){
//wenn die email verschickt werden konnte, wird der job auf done gesetzt
//und ein neuer job mit neuem versand datum angelegt
$update="update job set status='done' where jid=".$row['jid'];
mysql_query($update);
$time=getdate($row['remind_date']);
if($row['interval']=="d"){
$dstr=date("U", mktime($time['hours'], $time['minutes'], $time['seconds'],
$time['mon'], $time['mday']+1, $time['year']));
}
if($row['interval']=="w"){
$dstr=date("U", mktime($time['hours'], $time['minutes'], $time['seconds'],
$time['mon'], $time['mday']+7, $time['year']));
}
if($row['interval']=="m"){
$dstr=date("U", mktime($time['hours'], $time['minutes'], $time['seconds'],
$time['mon']+1, $time['mday'], $time['year']));
}
if($row['interval']=="y"){
$dstr=date("U", mktime($time['hours'], $time['minutes'], $time['seconds'],
$time['mon'], $time['mday'], $time['year']+1));
}
if($row['interval']!=="n"){
$update_setting="update reminder set remind_date=".$dstr." where rid=".$row[rid];
mysql_query($update_setting);
$insert="insert into job values ('', ".$row['rid'].", 'planned', ".$dstr.")";
mysql_query($insert);
}
}
}
?>
<?
include("./config.php");
$connect=@mysql_connect("$db_host", "$db_user", "$db_pass")
or die("<li>Cant connect to: $db_host with user: $db_user</li>");
@mysql_select_db($db, $connect)or die("Cant select DB");
// hier werden die letzen 10 jobs aus der datenbank geholt,
// der den staus planned hat und in der vergangenheit liegt.
$sql="SELECT jid, job.rid, subject, description, email, reminder.interval,
reminder.remind_date, reminder.auth
FROM job, reminder
WHERE
status='planned' AND
planned<UNIX_TIMESTAMP() AND
reminder.rid=job.rid
limit 10
";
$result=mysql_query($sql);
while($row=mysql_fetch_array($result)){
//setze job auf in bearbeitung, damit kein anderer prozess ihn ebenfalls erledigt
mysql_query("UPDATE job set staus='in_progress' where id='".$row['jid']."'");
$header = 'MIME-Version: 1.0' . "n";
$header .= 'Content-type: text/html; charset=iso-8859-1' . "n";
$header .= 'To: "'.$row['email'].'" <'.$row['email'].'>' . "n";
$header .= 'From: "Remind ME" <remind@codejungle.org>' . "n";
$msg='
<html>
<head>
<title>RemindME</title>
</head>
<body>
'.$row['description'].'
<br/><hr><a href="http://www.codejungle.org/reminder/uid/'.$row[auth].'">Modify your Reminder</a>
</body>
</html>
';
if(mail($row['email'], $row['subject'], $msg, $header)){
//wenn die email verschickt werden konnte, wird der job auf done gesetzt
//und ein neuer job mit neuem versand datum angelegt
$update="update job set status='done' where jid=".$row['jid'];
mysql_query($update);
$time=getdate($row['remind_date']);
if($row['interval']=="d"){
$dstr=date("U", mktime($time['hours'], $time['minutes'], $time['seconds'],
$time['mon'], $time['mday']+1, $time['year']));
}
if($row['interval']=="w"){
$dstr=date("U", mktime($time['hours'], $time['minutes'], $time['seconds'],
$time['mon'], $time['mday']+7, $time['year']));
}
if($row['interval']=="m"){
$dstr=date("U", mktime($time['hours'], $time['minutes'], $time['seconds'],
$time['mon']+1, $time['mday'], $time['year']));
}
if($row['interval']=="y"){
$dstr=date("U", mktime($time['hours'], $time['minutes'], $time['seconds'],
$time['mon'], $time['mday'], $time['year']+1));
}
if($row['interval']!=="n"){
$update_setting="update reminder set remind_date=".$dstr." where rid=".$row[rid];
mysql_query($update_setting);
$insert="insert into job values ('', ".$row['rid'].", 'planned', ".$dstr.")";
mysql_query($insert);
}
}
}
?>