Friday, August 30, 2013

Python with multiple versions of vtk

I like to keep my VTK up to date; some of my project unfortunately require older versions. So I thought of how to "activate" a particular package without having to swap .pth files in and out to my site-packages/ directory, but rather by setting up the more accessible PYTHONPATH environment variable. If vtk were a pure Python package, this would be all that were required, but we need the OS to find the right shared binary libraries as well, so we need to manipulate the OS PATH as well. In a .pth file, this can of course be done with an
import os; os.environ['PATH']='/path/to/vtk;'+os.environ['PATH']
in the .pth file, but then the lexically later .pth file name wins in prepending their os.environ['PATH']. A better way is to directly place the os stuff in the __init__.py files of the vtk packages, like so:
import re
x=os.path.realpath(__file__)
os.environ['PATH']=os.path.join(re.split('lib',x)[0],'bin')+';'+os.environ['PATH']
Admitted, it's ugly to have to edit this file, which gets generated during the build process, but hey, it works really well.

Friday, March 22, 2013

conquest dicom, dcmtk, Osirix test data and Slicer

For a project, I decided to have a look at Slicer. Since I am behind a corporate proxy the download of the demo data didn't work. So I decided to also roll a local Dicom Server and chose an old friend, Conquest DicomServer. I configured Conquest to use its own MySQL database, and to support JPEG2000 and store the images uncompressed with DCM file extension. Then I downloaded the Osirix sample dataset "PROSTATIX" from here. Turns out they are JPEG2000 compressed, and I needed a tool to store the images in Conquest. DCMTK and their storescu executable fit that bill. After tinkering with it for a while, I found that the -xv -xw cmd line options propose JPEG2000 lossless and lossy transfer:
storescu.exe -xv -xw +sd +sp *.dcm +r -aec CONQUESTSRV1 localhost 5678 ./
since I had entered
STORESCU  127.0.0.1 5678  un
as a known Dicom provider in Conquest where 'un' means uncompressed. I guess I could have specified another line
STORESCU_JL  127.0.0.1 5678  jl
and then called
storescu -aet STORESCU_JL ... 
. Anyway, the setup worked, and Conquest stored the files, responding
[CONQUESTSRV1] [recompress]: recompressed with mode = un (strip=0)
[CONQUESTSRV1] Written file: D:\data\conquest\91942\1.3.12.2.1107.5.1.4.48545.30000008100709320360900003740_0005_000437_13638632270744.dcm
Now I wanted to view the data in Slicer. After adding Conquest as a DICOM host in Slicer in the DICOM Module under "Dicom Browser->Query" and Slicer with its default AETITLE CTKSTORE, I was able to see the Osirix Dataset stored on Conquest. However, I was not able to retrieve it. I did get a Dialog Box saying that the Retrieve Process is finished", , but Looking at Slicer's log I see the following
Setting Transfer Syntaxes

About to retrieve 1.3.46.670589.5.2.10.2156913941.892665384.993397 from localhost
Starting to retrieve
Starting getStudy
Negotiating Association

I: Requesting Association
I: Association Accepted (Max Send PDV: 16372)

Setting Retrieve Parameters
Sending Get Request

setting value to 0
GET Request failed: No valid Study Root GET Presentation Context available

Retrieve success

I: Releasing Association
and no data in the Database! Here's the (useless) Conquest log:
[CONQUESTSRV1] UPACS THREAD 1605: STARTED AT: Fri Mar 22 16:31:18 2013
[CONQUESTSRV1] *** connection terminated
[CONQUESTSRV1] UPACS THREAD 1605: ENDED AT: Fri Mar 22 16:31:30 2013
[CONQUESTSRV1] UPACS THREAD 1605: TOTAL RUNNING TIME: 12 SECONDS
So what's going on? Here's the relevant snippet from
ctkDICOMRetrieve.cpp
:
//------------------------------------------------------------------------------
bool ctkDICOMRetrievePrivate::get ( const QString& studyInstanceUID,
                                         const QString& seriesInstanceUID,
                                         const RetrieveType retrieveType )
{
  Q_Q(ctkDICOMRetrieve);

  DcmDataset *retrieveParameters = new DcmDataset();
  if (! this->initializeSCU(studyInstanceUID, seriesInstanceUID, retrieveType, retrieveParameters) )
    {
    delete retrieveParameters;
    return false;
    }

  // Issue request
  logger.debug ( "Sending Get Request" );
  emit q->progress("Sending Get Request");
  emit q->progress(0);
  OFList responses;
  T_ASC_PresentationContextID presID = this->SCU.findPresentationContextID(
                                          UID_GETStudyRootQueryRetrieveInformationModel, 
                                          "" /* don't care about transfer syntax */ );
  if (presID == 0)
    {
    logger.error ( "GET Request failed: No valid Study Root GET Presentation Context available" );
    if (!this->KeepAssociationOpen)
      {
      this->SCU.closeAssociation(DCMSCU_RELEASE_ASSOCIATION);
      }
    delete retrieveParameters;
    return false;
    }

  emit q->progress("Found Presentation Context");
  emit q->progress(1);
Apparently the SCU.findPresentationContextID call didn't return a Presentation Context, but I don't understand why.

Wednesday, February 13, 2013

Testing MathJax on Blogger

You should see the time-dependent Schroedinger Equation here:

   2 2 m 2 x 2 + V Ψ = i t Ψ

courtesy of a simple new line in the Blogger template. Right-clicking it will allow you to copy it in MathML, since it was written this way. The equation below was written in LaTeX, so I can be copied out as such. This is so cool!

This is a test for inline LaTeX: \(\frac{a}{b}\).
And here we have a nice limit as an equation: $$\lim_{x \to \infty} \exp(-x) = 0$$. This was written as LaTeX
$$\lim_{x \to \infty} \exp(-x) = 0$$
and must be entered with the $$ delimiters on Blogger's HTML tab, otherwise the Blogger formatter will mangle it.

Mongo, Django and the Admin View - work in progress

Once you switch Django to a MongDB backend with MongoEngine (see my previous posts), you loose Django's automatic admin view. This is a pity since it's such a nice web CRUD interface. There are some options though to get it back, among them mongoadmin Since I like working with Django 1.6 dev trunk, I needed to adapt mongoadmin in two spots: options.py and sites.py.

Here are the diffs of the changes I have made so far, without breaking backward compatibility, however surfing to the admin page still throws an error, so I will update this page when I get a chance and not commit (yet). Perhaps it's already useful for somebody - comments welcome!

For options.py
@@ -11,7 +11,11 @@
 from django.db import models, transaction, router
 from django.db.models.related import RelatedObject
 from django.db.models.fields import BLANK_CHOICE_DASH, FieldDoesNotExist
-from django.db.models.sql.constants import QUERY_TERMS, LOOKUP_SEP
+from django.db.models.sql.constants import QUERY_TERMS
+try:
+  from django.db.models.sql.constants import LOOKUP_SEP
+except ImportError:
+  from django.db.models.constants import LOOKUP_SEP
 from django.http import Http404, HttpResponse, HttpResponseRedirect
 from django.shortcuts import get_object_or_404, render_to_response
 from django.utils.decorators import method_decorator

For sites.py
@@ -207,7 +207,10 @@
         return update_wrapper(inner, view)

     def get_urls(self):
-        from django.conf.urls.defaults import patterns, url, include
+        try:
+            from django.conf.urls.defaults import patterns, url, include
+        except ImportError:
+            from django.conf.urls import patterns, url, include

         if settings.DEBUG:
             self.check_dependencies()


BTW, I've started to use SyntaxHighlighter for code. Thanks Alex!

Mongo and Django

Like I described in the last post, I installed mongo and its python API mongoengine. Now I wanted to see if I could connect it to my preferred Python Web framework, Django.  A very nice tutorial on IBM DeveloperWorks got me interested in trying this too.

I use Eclipse and the very nice PyDev Python plug-in for Django development. The latter offers a little bit of Django integration into Eclipse, so a had a bare-bones Django site in no time at all, with the standard settings.py file. At this point, the site was based on SqlLite, Django's default.

Now the first bit is to connect to MongoDB inside settings.py, following the Mongoengine tutorial, like so:


import mongoengine  

 
 DEBUG = True  
 TEMPLATE_DEBUG = DEBUG  
 ADMINS = (  
   # ('Your Name', 'your_email@example.com'),  
 )  
 MANAGERS = ADMINS  
 DATABASES = {  
   'default': {  
     'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.  
     'NAME': 'C:\\Users\\me\\src\\test\\django_mongo\\sqlite.db',           # Or path to database file if using sqlite3.  
     # The following settings are not used with sqlite3:  
     'USER': '',  
     'PASSWORD': '',  
     'HOST': '',           # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP.  
     'PORT': '',           # Set to empty string for default.  
   }  
 }  


 print 'Connection to MongoDB...',  
 mongoengine.connect('test')  
 print 'connected.'  

Additional lines that go to the bottom of settings.py are

 
AUTHENTICATION_BACKENDS = (  
   'mongoengine.django.auth.MongoEngineBackend',  
 )  
 SESSION_ENGINE = 'mongoengine.django.sessions'  

At this point I was able to run the Django shell, but of course had no models to play with. So I made an app with the standard Django manage.py startapp replicated the ones from the tutorial, except for the User model, which I imported from the mongoengine auth backend:

 from mongoengine import *  
 from mongoengine.django.auth import User  
   
 # Create your models here.  
 class Comment(EmbeddedDocument):  
   content = StringField()  
   name = StringField(max_length=120)  
   
 class Post(Document):  
   title = StringField(max_length=120, required=True)  
   author = ReferenceField(User, reverse_delete_rule=CASCADE)  
   tags = ListField(StringField(max_length=30))  
   comments = ListField(EmbeddedDocumentField(Comment))  
   
 class TextPost(Post):  
   content = StringField()  
   
 class ImagePost(Post):  
   image_path = StringField()  
   
 class LinkPost(Post):  
   link_url = StringField()  
   

Back in the Django shell, I got some FutureWarnings regarding inheritance soon defaulting to off, but I successfully tested
 In [2]: c=Comment(content='lala', name='Useful comment')  
 In [3]: u=User()  
 In [4]: u.username='me'  
 ...  
 In [30]: u  
 Out[30]: <User: me>  
   
 In [31]: User.objects.all()  
 Out[31]: []  
   
 In [32]: u.save()  
 Out[32]: <User: me>  
   
 In [33]: User.objects.all()  
 Out[33]: [<User: me>]  
   
 In [35]: p=Post(title='T', author=u, tags=['t1','t2'], comments=[c])  
   
 In [36]: p.save()  
 Out[36]: <Post: Post object>  
   
 In [38]: Post.objects.all()  
 Out[38]: [<Post: Post object>]  
   
 In [39]: Post.objects.all()[0]  
 Out[39]: <Post: Post object>  
   
 In [40]: Post.objects.all()[0].comments  
 Out[40]: [<Comment: Comment object>]  
   
 In [41]: Post.objects.filter(title='A')  
 Out[41]: []  
   
 In [42]: Post.objects.filter(title='T')  
 Out[42]: [<Post: Post object>]  
   
 In [43]: Post.objects.filter(title__in=['A','T'])  
 Out[43]: [<Post: Post object>]  

But I did get stuck at joins that span relations:
 In [54]: Post.objects.filter(author__username='me')  
 Out[54]: ---------------------------------------------------------------------------  
 InvalidQueryError             Traceback (most recent call last)  

Either I got something wrong or a bug tripped me! I will definitely crosspost this at Mongoengine and StackOverflow.

BTW, this was done with Django 1.6 20130110 dev trunk and Mongoengine 0.7.9 .

Tuesday, February 12, 2013

MongoDB on Windows

We just had a very nice overview talk on MongoDB, so I wanted to give it a shot, especially its Python interface Mongoengine and installed it on my notebook. Turns out installing is just as easy as the docu said. Unzip the package from Mongo's download page into the directory of your choice, create a cfg file with two entries,
dbpath pointing to the directory where Mongo will place its DB files and logpath pointing to the log file.

Then install it as a service in a shell with administrator rights:


D:\>d:\packages\mongodb-win32-x86_64-2008plus-2.2.3\bin\mongod.exe --config c:\U
sers\me\mongodb.cfg --install
all output going to: D:\logs\mongo.log

D:\>net start MongoDB

The Mongo DB service was started successfully.

D:\>


The installation can be immediately tested with mongo.exe:


C:\Users\usd22492>d:\packages\mongodb-win32-x86_64-2008plus-2.2.3\bin\mongo.exe
MongoDB shell version: 2.2.3
connecting to: test
Welcome to the MongoDB shell.
For interactive help, type "help".
For more comprehensive documentation, see
        http://docs.mongodb.org/
Questions? Try the support group
        http://groups.google.com/group/mongodb-user


Now on to the even simpler installation of MongoEngine (provided Python and pip are already onboard):

pip install -U mongoengine

Just like the docu says.


'via Blog this'

Tuesday, January 22, 2013

cygwin svn behind a firewall

At work, I am behind a firewall. I knew that I had to generally configure cygwin to deal with the proxy by setting the env var HTTP_PROXY, but subversion still failed. Usually I can do svn operations through the wonderful TortoiseSVN windows suite, but building TubeTK  somehow insisted on using cygwn svn, even though I had set the svn parameter in the CMake configuration to use TortoiseSvn, and yes, I did make sure that cywin wasn't in CMakeCache.txt for the build. Some googling brought me to this post where Pascal explains it;


edit ~/.subversion/servers. In the [global] section, use these lines:
[global]
http-proxy-host = your.server.address
http-proxy-port = your_server_port

Works! Easy when you know!

Wednesday, January 16, 2013

WAMP stack and Joomla on Windows 7

The public web site for our new DR THERAPAT EU-funded project should be backed by a CMS - I thought Joomla might be nice. For testing, I installed a WAMP stack based on Win 7 machine at work. I already had MySql, otherwise I would have used XAMPP or something similar. I pretty much folllowed this blog entry, except for the bit about "Extract php5apache2_4.dll-php-5.4-win32.zip and copy php5apache2_4.dll into the ext/" directory, since I found the dll already present. I also put the packages somewhere else, which necessitated changing the conf files, but nothing unexpected was needed. I also installed phpMyAdmin and used its setup to configure it to use mysqli for DB access.

The Joomla doc lists dependencies on Apache modules mod_mysql, mod_xml and mod_zlib. This is plain wrong. What is meant is the php_ modules!! Now, since I have PHP 5.4.10, all this is very simple since mysqlnd, the native mysql driver, is already compiled into php. I just needed to configure php.ini correctly

extension_dir = ".\ext"

and


extension=php_mysql.dll
extension=php_mysqli.dll

Going to http://localhost:8000/phpMyAdmin now correctly shows the phpMyAdmin login page. 

Then installing Joomla is matter of extracting its downloaded zip into a joomla subdir to Apache's htdocs. This for testing only, I assume for a real web site I'll have to put it somewhere else.

Then going to localhost:8000/joomla, I just needed to go through Joomla' configuration pages, nothing unexpected here. Of course, I had set up a new schema in MySQL beforehand. And voila, my Joomla site showed up with standard content!

Now I need to learn how to program it, but it can't be much different from Drual which I used for my wife's web site at releaseintopeace.net.

'via Blog this'