tags:

views:

66

answers:

1

I'm trying to build some image algebra code that can work with images (basically a linear pixel buffer + dimensions) that have different types for the pixel. To get this to work, I've defined a parametrized Pixel trait with a few methods that should be able to get used with any Pixel subclass. (For now, I'm only interested in operations that work on the same Pixel type.) Here it is:

trait Pixel[T <: Pixel[T]] {
    def div(v: Double): T
    def div(v: T): T
}

Now I define a single Pixel type that has storage based on three doubles (basically RGB 0.0-1.0), I've called it TripleDoublePixel:

class TripleDoublePixel(v: Array[Double]) extends Pixel[TripleDoublePixel] {

    var data: Array[Double] = v

    def this() = this(Array(0.0, 0.0, 0.0))

    def div(v: Double): TripleDoublePixel = {
        new TripleDoublePixel(data.map(x => x / v))
    }

    def div(v: TripleDoublePixel): TripleDoublePixel = {
        var tmp = new Array[Double](3)
        tmp(0) = data(0) / v.data(0)
        tmp(1) = data(1) / v.data(1)
        tmp(2) = data(2) / v.data(2)
        new TripleDoublePixel(tmp)
    }

}

Then we define an Image using Pixels:

class Image[T](nsize: Array[Int], ndata: Array[T]) {

    val size: Array[Int] = nsize
    val data: Array[T] = ndata

    def this(isize: Array[Int]) {
        this(isize, new Array[T](isize(0) * isize(1)))
    }

    def this(img: Image[T]) {
        this(img.size, new Array[T](img.size(0) * img.size(1)))
        for (i <- 0 until img.data.size) {
            data(i) = img.data(i)
        }
    }

}

(I think I should be able to do without the explicit declaration of size and data, and use just what has been named in the default constructor, but I haven't gotten that to work.)

Now I want to write code to use this, that doesn't have to know what type the pixels are. For example:

def idiv[T](a: Image[T], b: Image[T]) {
    for (i <- 0 until a.data.size) {
        a.data(i) = a.data(i).div(b.data(i))
    }
}

Unfortunately, this doesn't compile:

(fragment of lindet-gen.scala):145:
error: value div is not a member of T
                 a.data(i) = a.data(i).div(b.data(i))

I was told in #scala that this worked for someone else, but that was on 2.8. I've tried to get 2.8-rc1 going, but the RC1 doesn't compile for me. Is there any way to get this to work in 2.7.7?

+5  A: 

Your idiv function has to know it'll actually be working with pixels.

def idiv[T <: Pixel[T]](a: Image[T], b: Image[T]) {
    for (i <- 0 until a.data.size) {
        a.data(i) = a.data(i).div(b.data(i))
    }
}

A plain type parameter T would define the function for all possible types T, which of course don't all support a div operation. So you'll have to put a generic constraint limiting the possible types to Pixels.

(Note that you could put this constraint on the Image class as well, assuming that an image out of something different than pixels doesn't make sense)

Dario
Doh. That makes perfect sense, thanks.
djc