예제 #1
0
파일: morph.py 프로젝트: SRabbelier/Casam
def createMorph(selectedImages,selectedPMs):
  """
  Translates and rotate the bitmaps based on the shapedefining landmarks (selectedPMs)
  of the associated image to the target image (first image).
  Morphs the result so that the bitmap overlay on the first image is valid for the first image.  
  """
  
  #save the temporary results here later:
  os_temp_path = tempfile.gettempdir()
  
  #get the measurements for the first image (our targets)
  mainImage = OriginalImage.objects.all().get(id=selectedImages[0])
  potentialids = [] 
  #now get the associated measurements
  measures = Measurement.objects.all().filter(id__in=selectedPMs[0]).filter(mogelijkemeting__shapedefining=True)
  measures = [j for j in measures]
  measures.sort(key=lambda x: x.mogelijkemeting.name)
   
  coordsx = []
  coordsy = []
  for k, measurement in enumerate(measures):
    coordsx.append(float(measurement.x))
    coordsy.append(float(measurement.y))
    potentialids.append(measurement.mogelijkemeting.id)
  r1 = vtk.vtkJPEGReader()
  r1.SetFileName(settings.DATADIR + mainImage.id + ".jpg")
  r1.Update() 

  # flip y coord (VTK has opposite convention), create 3-d coords (z=0)
  ydim = r1.GetOutput().GetDimensions()[1]
  coords = [(x, ydim - y, 0) for (x,y) in zip(coordsx, coordsy)]
  
  # convert everything to vtkPoints
  lmt = vtk.vtkPoints()
  lmt.SetNumberOfPoints(len(coords))
  for i, coord in enumerate(coords):
    lmt.SetPoint(i,coord)
  
  #The target is clear, let's get to work, get the source images...
  images = []
  #we don't need the first image or its measures anymore, because they don't need to be transformed or morphed
  selectedImages.pop(0)
  selectedPMs.pop(0)
  for id in selectedImages:
    images.append(OriginalImage.objects.all().get(id=id))

  transformations = []
  morphtransformations = []
  
  #Create a new database object for the target image to associate the bitmaps with
  img = OriginalImage(project=mainImage.project, name='MorphedImage')
  img.save()
  imp = Image.open(settings.DATADIR + mainImage.id + '.jpg')
  imp.save(settings.DATADIR + img.id + '.jpg', 'JPEG')  
  orig_bitmaps = Bitmap.objects.all().filter(image=mainImage)
  
  for bm in orig_bitmaps:
    #store bitmaps of mainImage as sub of img
    bitmap = Bitmap(project=img.project, name='warpedbitmap', image=img, 
                      mogelijkemeting=bm.mogelijkemeting, imagewidth=bm.imagewidth, 
                      imageheight=bm.imageheight, minx=bm.minx, miny=bm.miny, maxx=bm.maxx, maxy=bm.maxy)
    bitmap.save()
      
    bitmap_image = Image.open(settings.DATADIR + bm.id + '.gif')
    bitmap_image = bitmap_image.convert("RGBA")
    bitmap_image.save(settings.DATADIR + bitmap.id + '.gif', transparency=0)
    
  #now get the other images and perform our transformations
  for i in range(len(images)):
    measures = Measurement.objects.all().filter(id__in=selectedPMs[i]).filter(mogelijkemeting__shapedefining=True)#get measurements
    measures = [j for j in measures]
    measures.sort(key=lambda x: x.mogelijkemeting.name)
    coordsx = []
    coordsy = []    
    for k, measurement in enumerate(measures):
      coordsx.append(float(measurement.x))
      coordsy.append(float(measurement.y))
      if potentialids[k] != measurement.mogelijkemeting.id: #the potentialmeasurements do not match up to the ones in the target image
        return img, 0
    r = vtk.vtkJPEGReader()
    r.SetFileName(settings.DATADIR + images[i].id + ".jpg")
    r.Update()

    ydim = r.GetOutput().GetDimensions()[1]
    coordso = [(x, ydim - y, 0) for (x,y) in zip(coordsx, coordsy)]
    lms = vtk.vtkPoints()
    lms.SetNumberOfPoints(len(coordso))
    for k, coord in enumerate(coordso):
      lms.SetPoint(k,coord)

    transformation = vtk.vtkLandmarkTransform()
    transformation.SetTargetLandmarks(lmt)  
    lmt.Modified()
    transformation.SetSourceLandmarks(lms)
    lms.Modified()
    #size matters, so set the mode to Rigid Body (also known as do not scale please)
    transformation.SetModeToRigidBody()
    transformation.Inverse()
    transformation.Update()
    out = vtk.vtkPoints()#this will be the source of our morph transform
    transformation.TransformPoints(lms,out)
    transformations.append(transformation)
    ir = vtk.vtkImageReslice()
    # we're not using linear, because we want to improve the quality of the bitmaps
    ir.SetInterpolationModeToNearestNeighbor()
    ir.SetResliceTransform(transformation)
    ir.SetInput(r.GetOutput())
    ir.SetInformationInput(r1.GetOutput())
    w = vtk.vtkJPEGWriter()
    w.SetFileName(os_temp_path+'/translated'+images[i].id+'.jpg')
    w.SetInput(ir.GetOutput())
    w.Write()
    r2 = vtk.vtkJPEGReader()
    r2.SetFileName(os_temp_path+'/translated'+images[i].id+'.jpg')
    r2.Update()  
 
    # the mighty morphing ThinPlateSplineTransform
    morphtransform = vtk.vtkThinPlateSplineTransform()
    morphtransform.SetBasisToR2LogR()
    morphtransform.SetSourceLandmarks(lms)
    lms.Modified()
    morphtransform.SetTargetLandmarks(lmt)
    lmt.Modified()
    morphtransform.Inverse()
    morphtransform.Update()
    morphtransformations.append(morphtransform)

    #ir.SetInput(r2.GetOutput())
    #ir.SetInformationInput(r1.GetOutput())
    
    bitmaps = Bitmap.objects.all().filter(image=images[i])
    
    #now perform the total transformation on all bitmaps
    for bm in bitmaps:
      location = settings.DATADIR + bm.id + ".gif"
      im = Image.open(location)
      im = im.convert("RGBA")
      im.save(settings.DATADIR + bm.id + ".png", "PNG")

      r3 = vtk.vtkPNGReader()
      r3.SetFileName(settings.DATADIR + bm.id + '.png')
      r3.Update()
      
      ir2 = vtk.vtkImageReslice()
      ir2.SetInterpolationModeToNearestNeighbor()
      ir2.SetResliceTransform(morphtransform)
      ir2.SetInput(r3.GetOutput())
      ir2.SetInformationInput(r2.GetOutput())
      
      w3 = vtk.vtkPNGWriter()
      w3.SetFileName(os_temp_path+'/morphed'+bm.id+'.png')
      w3.SetInput(ir2.GetOutput())
      w3.Write()
      
      bitmap = Bitmap(project=img.project, name='warpedbitmap', image=img, 
                      mogelijkemeting=bm.mogelijkemeting, imagewidth=bm.imagewidth, 
                      imageheight=bm.imageheight, minx=bm.minx, miny=bm.miny, maxx=bm.maxx, maxy=bm.maxy)
      bitmap.save()
      
      im = Image.open(os_temp_path+'/morphed'+bm.id+'.png')
      im = im.convert("RGBA")
      im.save(settings.DATADIR + bitmap.id + '.gif', transparency=0)
      

  return img, 1
예제 #2
0
def handle_bitmap_stream(dump,original_image,previous_id,r,g,b,mm):
  """ With the string representation of a bitmap; the original_image
     this bitmap is painted over; the id of the previous bitmap;
     the color information and the id of the possible measurement
     this function saves the dump as a .gif-file and puts it in the db.
  """ 

  # Check the header
  if dump == "_empty":
    print "Empty bitmap submitted"
    return previous_id

  # Initialise color information
  if not (r >= 0 and r <= 255 and 
          g >= 0 and g <= 255 and 
          b >= 0 and b <= 255):
    r = 255
    g = 0
    b = 0
    
  #backgroundColor = ((r << 16) & 0xFF) + ((g << 8) & 0xFF) + (b & 0xFF);
    
  # Split dump in header and body
  dump = dump.split("#")
  header = dump[0].split("x")
  body = dump[1]

  # Check the header
  if header[0] != "_scanline:":
    print "wrong dump"
    return

  # Load needed variables from header
  total_width  = int(header[1])
  total_height = int(header[2])
  min_x = int(header[3])
  max_x = int(header[4])
  min_y = int(header[5])
  max_y = int(header[6])
  
  
  # Derive needed variables from loaded variables
  block_width  = max_x - min_x + 1
  block_height = max_y - min_y + 1


  skip_before = min_y * total_width + min_x
  skip_between = min_x + (total_width - 1 - max_x)
  skip_after = (total_height - 1 - max_y) * total_width + (total_width - 1 - max_x)
  
  # Create string to fill before and after block
  fill_before  = ''.zfill(skip_before).replace('0',chr(0))
  fill_after   = ''.zfill(skip_after).replace('0',chr(0))
  
  # Keep track of the amount of pixels that is currently on the line
  # in the block to be able to determine how often we need to add skip_between
  line_fill = 0
  
  # Make decode bit-stream
  stream = fill_before 
 
  # Do as long as there is still data in body
  while len(body) > 1:
    
    # Find number of black pixels
    end = body.find("b")
    i = int(body[:end])
    body = body[end+1:]
    
    # We need at least to add i pixels
    line_fill += i
    
    # Each whole amount block_with fits in line_fill,
    # we need to add skip_between
    
    while line_fill > block_width:
      
      i += skip_between
      line_fill -= block_width
      
    # Write i background pixels to the bit-stream
    stream += ''.zfill(i).replace('0',chr(0))

    # Stop if we now finished the end of the string data
    if len(body) < 2: break;
  
    # Now do the foreground
    end = body.find("f")
    i = int(body[:end])
    body = body[end+1:]
    
    # If we now need to add lines, it should
    # also be background outside the block
    if line_fill + i > block_width:
      
      # First write foreground pixels to fill the current row in the block
      stream += ''.zfill(block_width - line_fill).replace('0', chr(255))
      
      # We still have this much pixels to write
      line_fill = i - (block_width - line_fill)
      
      # As long as we can fill full block lines 
      while line_fill > block_width:

        # First write background line to get back to block
        stream += ''.zfill(skip_between).replace('0', chr(0))
        
        # Then write a full line foreground-data
        stream += ''.zfill(block_width).replace('0', chr(255))
        line_fill -= block_width

      # Return to a new line (by filling space outside the block)
      stream += ''.zfill(skip_between).replace('0', chr(0))

      # We still have a number of pixels left to write
      i = line_fill
    
    # Otherwise we also need to remember this set of pixels
    else:
      line_fill += i
 
    # Write to the bit-stream
    stream += ''.zfill(i).replace('0',chr(255))

  stream += fill_after
  
  # Build image
  im = Image.fromstring("L",(total_width,total_height), stream, "raw", "L")
  
  # Attach palette
  im.convert("P")
  palette = []
  for i in range(256):
    palette.extend((0, 0, 0))

  palette[0] = 0
  palette[1] = 0
  palette[2] = 0

  palette[765] = r  
  palette[766] = g
  palette[767] = b

  assert len(palette) == 768
  
  im.putpalette(palette)
  
  # Make database insert
  if previous_id == '0':    
    # Create associated measurement
    properties = dict(
      image = original_image,
      mogelijkemeting = mm,
      imagewidth = int(total_width),
      imageheight = int(total_height),
      minx = min_x,
      maxx = max_x,
      miny = min_y,
      maxy = max_y,
      project = original_image.project,
      name = "bitmap",
    )
    db_bitmap = Bitmap(**properties)
    db_bitmap.save()

    
    img_path = os.path.join(settings.DATADIR, db_bitmap.id + ".gif")
    
    im.save(img_path, transparency=0)
    return db_bitmap.id
  
  # Just overwrite previous image-file
  else:
    previous_image = Bitmap.objects.all().get(id=previous_id)
    previous_image.minx = min_x
    previous_image.maxx = max_x
    previous_image.miny = min_y
    previous_image.maxy = max_y
    previous_image.save()
    
    image_path = os.path.join(settings.DATADIR, previous_image.id + '.gif')
    
    im.save(image_path, transparency=0)
    
    return previous_id