Skip to content
This repository has been archived by the owner on Oct 4, 2020. It is now read-only.

Method for exposing the raw data #104

Closed
wants to merge 9 commits into from
51 changes: 51 additions & 0 deletions rawkit/raw.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,57 @@ def save_thumb(self, filename=None):
self.libraw.libraw_dcraw_thumb_writer(
self.data, filename.encode('ascii'))

def get_4_col_raw(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another thing I'm thinking (though this doesn't have to be done right now by any means, I just wanted to comment while I was thinking about it so that it was documented somewhere) is that the public facing API method for this should just work for all types of raws (regardless of how many channels there are). @campaul and I will probably sit down sometime this weekend and figure out a more unified API (including return values and types) for all methods that return image data like this. Will advise.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi.

It is easy to change this to the other case (with only 3 colours), as the data then is in color3_image and not in color4_image. Though before I modify this I would like to know what the return types should be. In my mind we should return something that is 2D, as this removes the need to pass along height and width.

"""
Read the 4 colour raw data
The returned numpy array is (given colour RGGB)
---------
R B R B ...
G B G B ...
R B R B ....
. . . . .
. . . . .
. . . . .
--------


Returns:
array: 4 colour data of the image in unit16. (width x height)
str : colour channel description (ie. RGGB, RGBG)
"""
# Unpack the data, so that rawdata is populated
self.unpack()
rawdata = self.data.contents.rawdata

# Return None if the image isn't 4 colour, which will happen for some
# cameras

try:
rawdata.color4_image.contents
except:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, this makes sense, thanks! Let's catch the actual exception here though; bare excepts can have unintended side effects :)

return None

# Get image size
iheight = rawdata.sizes.iheight
iwidth = rawdata.sizes.iwidth

# Make pointer to data

data_pointer = ctypes.cast(
rawdata.color4_image.contents,
ctypes.POINTER(ctypes.c_ushort)
)

# make 2D list
data = [[0 for i in range(iheight)] for j in range(iwidth)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be cleaner, no idea if there's a "standard" way to do this in Python:

data = [None] * iheight * iwidth

It might be a pre-mature optimization either way though. Or I may be completely wrong. Just thinking out loud. @campaul?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It needs to be 2D, or you'll have to pass height and width on, and let the calling function do the reshape.
From what I understood, list compression is the normal way of initialising this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good then. I think the above will make a 2d list too, but I could be mistaken. If we're going to have to iterate anyways though I think we might as well not preallocate.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A quick quick test gives it as a 1D.
As for the preallocate, I like it due to the large lists being created, though I don't know what is fastest.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're going to loop and append, 0's though we might as well just loop and append the data. I'm not sure this is actually an optimization, unless Python does some sort of optimization on simple list comprehensions that I don't know about.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would probably be more efficient. I'll do some timings later and see for sure.

data = [[] for j in range(iwidth)]

for ii in range(iheight):
    for jj in range(iwidth):
        data[jj].append(data_pointer[ii * iwidth + jj])


for ii in range(iheight):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we change ii and jj to y and x respectively so we're working with Cartesian coordinates?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These aren't actually coordinates on the image though since there are multiple indexes per pixel.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They will be coordinates, though you have to interpolate the image first, as in that loop they change between different colour channels.

for jj in range(iwidth):
data[jj][ii] = data_pointer[ii * iwidth + jj]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still appears to be subscripting a 2D array; won't this be broken?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my test run this works as intended.
Though I'm not sure what you think would be broken?
Line 221 makes a 2D list, which one can index with [][] in line 225

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh right, yah, I was misunderstanding a large chunk of our discussion, sorry. I think it's best to make this a 1D list to match the data that we get from LibRaw / elsewhere in rawkit. Not sure though; will consider the API implications of doing this and get back to you. It's not super important right now.


# Return data and colour descriptor
return data, self.data.contents.idata.cdesc

def to_buffer(self):
"""
Convert the image to an RGB buffer.
Expand Down