Issue 2139: extended camconst.json to handle raw crop
This commit is contained in:
100
rtengine/camconst.cc
Normal file → Executable file
100
rtengine/camconst.cc
Normal file → Executable file
@@ -22,6 +22,8 @@ extern const Settings* settings;
|
||||
CameraConst::CameraConst()
|
||||
{
|
||||
memset(dcraw_matrix, 0, sizeof(dcraw_matrix));
|
||||
memset(raw_crop, 0, sizeof(raw_crop));
|
||||
memset(raw_mask, 0, sizeof(raw_mask));
|
||||
white_max = 0;
|
||||
}
|
||||
|
||||
@@ -96,16 +98,29 @@ CameraConst::parseLevels(CameraConst *cc, int bw, void *ji_)
|
||||
}
|
||||
|
||||
for (ji = ji->child; ji != NULL; ji = ji->next) {
|
||||
int iso = 0;
|
||||
int iso[1000] = { 0 };
|
||||
int iso_count = 0;
|
||||
cJSON *js = cJSON_GetObjectItem(ji, "iso");
|
||||
if (!js) {
|
||||
fprintf(stderr, "missing \"ranges\":\"%s\":\"iso\" object item.\n", bw ? "white" : "black");
|
||||
return false;
|
||||
} else if (js->type != cJSON_Number) {
|
||||
fprintf(stderr, "\"ranges\":\"%s\":\"iso\" must be a a number.\n", bw ? "white" : "black");
|
||||
} else if (js->type == cJSON_Number) {
|
||||
iso[0] = js->valueint;
|
||||
iso_count = 1;
|
||||
} else if (js->type == cJSON_Array) {
|
||||
int i;
|
||||
for (js = js->child, i = 0; js != NULL && i < 1000; js = js->next, i++) {
|
||||
if (js->type != cJSON_Number) {
|
||||
fprintf(stderr, "\"ranges\":\"%s\":\"iso\" must be a number or an array of numbers.\n", bw ? "white" : "black");
|
||||
return false;
|
||||
}
|
||||
iso[i] = js->valueint;
|
||||
}
|
||||
iso_count = i;
|
||||
} else {
|
||||
fprintf(stderr, "\"ranges\":\"%s\":\"iso\" must be an array or a number.\n", bw ? "white" : "black");
|
||||
return false;
|
||||
}
|
||||
iso = js->valueint;
|
||||
js = cJSON_GetObjectItem(ji, "levels");
|
||||
if (!js) {
|
||||
fprintf(stderr, "missing \"ranges\":\"%s\":\"levels\".\n", bw ? "white" : "black");
|
||||
@@ -135,7 +150,9 @@ CameraConst::parseLevels(CameraConst *cc, int bw, void *ji_)
|
||||
fprintf(stderr, "\"ranges\":\"%s\":\"levels\" must be a number or an array of numbers.\n", bw ? "white" : "black");
|
||||
return false;
|
||||
}
|
||||
cc->mLevels[bw].insert(std::pair<int,struct camera_const_levels>(iso, lvl));
|
||||
for (int i = 0; i < iso_count; i++) {
|
||||
cc->mLevels[bw].insert(std::pair<int,struct camera_const_levels>(iso[i], lvl));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -165,6 +182,44 @@ CameraConst::parseEntry(void *cJSON_, const char *make_model)
|
||||
cc->dcraw_matrix[i] = (short)ji->valueint;
|
||||
}
|
||||
}
|
||||
ji = cJSON_GetObjectItem(js, "raw_crop");
|
||||
if (ji) {
|
||||
if (ji->type != cJSON_Array) {
|
||||
fprintf(stderr, "\"raw_crop\" must be an array\n");
|
||||
goto parse_error;
|
||||
}
|
||||
int i;
|
||||
for (i = 0, ji = ji->child; i < 4 && ji != NULL; i++, ji = ji->next) {
|
||||
if (ji->type != cJSON_Number) {
|
||||
fprintf(stderr, "\"raw_crop\" array must contain numbers\n");
|
||||
goto parse_error;
|
||||
}
|
||||
cc->raw_crop[i] = ji->valueint;
|
||||
}
|
||||
if (i != 4 || ji != NULL) {
|
||||
fprintf(stderr, "\"raw_crop\" must contain 4 numbers\n");
|
||||
goto parse_error;
|
||||
}
|
||||
}
|
||||
ji = cJSON_GetObjectItem(js, "masked_areas");
|
||||
if (ji) {
|
||||
if (ji->type != cJSON_Array) {
|
||||
fprintf(stderr, "\"masked_areas\" must be an array\n");
|
||||
goto parse_error;
|
||||
}
|
||||
int i;
|
||||
for (i = 0, ji = ji->child; i < 8 * 4 && ji != NULL; i++, ji = ji->next) {
|
||||
if (ji->type != cJSON_Number) {
|
||||
fprintf(stderr, "\"masked_areas\" array must contain numbers\n");
|
||||
goto parse_error;
|
||||
}
|
||||
cc->raw_mask[i/4][i%4] = ji->valueint;
|
||||
}
|
||||
if (i % 4 != 0) {
|
||||
fprintf(stderr, "\"masked_areas\" array length must be divisable by 4\n");
|
||||
goto parse_error;
|
||||
}
|
||||
}
|
||||
jranges = cJSON_GetObjectItem(js, "ranges");
|
||||
if (jranges) {
|
||||
ji = cJSON_GetObjectItem(jranges, "black");
|
||||
@@ -236,6 +291,41 @@ CameraConst::get_dcrawMatrix(void)
|
||||
return dcraw_matrix;
|
||||
}
|
||||
|
||||
bool
|
||||
CameraConst::has_rawCrop(void)
|
||||
{
|
||||
return raw_crop[0] != 0 || raw_crop[1] != 0 || raw_crop[2] != 0 || raw_crop[3] != 0;
|
||||
}
|
||||
|
||||
void
|
||||
CameraConst::get_rawCrop(int& left_margin, int& top_margin, int& width, int& height)
|
||||
{
|
||||
left_margin = raw_crop[0];
|
||||
top_margin = raw_crop[1];
|
||||
width = raw_crop[2];
|
||||
height = raw_crop[3];
|
||||
}
|
||||
|
||||
bool
|
||||
CameraConst::has_rawMask(int idx)
|
||||
{
|
||||
if (idx < 0 || idx > 7)
|
||||
return false;
|
||||
return (raw_mask[idx][0] | raw_mask[idx][1] | raw_mask[idx][2] | raw_mask[idx][3]) != 0;
|
||||
}
|
||||
|
||||
void
|
||||
CameraConst::get_rawMask(int idx, int& top, int& left, int& bottom, int& right)
|
||||
{
|
||||
top = left = bottom = right = 0;
|
||||
if (idx < 0 || idx > 7)
|
||||
return;
|
||||
top = raw_mask[idx][0];
|
||||
left = raw_mask[idx][1];
|
||||
bottom = raw_mask[idx][2];
|
||||
right = raw_mask[idx][3];
|
||||
}
|
||||
|
||||
void
|
||||
CameraConst::update_Levels(const CameraConst *other) {
|
||||
if (!other)
|
||||
|
6
rtengine/camconst.h
Normal file → Executable file
6
rtengine/camconst.h
Normal file → Executable file
@@ -17,6 +17,8 @@ class CameraConst {
|
||||
private:
|
||||
Glib::ustring make_model;
|
||||
short dcraw_matrix[12];
|
||||
int raw_crop[4];
|
||||
int raw_mask[8][4];
|
||||
int white_max;
|
||||
std::map<int, struct camera_const_levels> mLevels[2];
|
||||
std::map<float, float> mApertureScaling;
|
||||
@@ -32,6 +34,10 @@ class CameraConst {
|
||||
bool has_dcrawMatrix(void);
|
||||
void update_dcrawMatrix(const short *other);
|
||||
const short *get_dcrawMatrix(void);
|
||||
bool has_rawCrop(void);
|
||||
void get_rawCrop(int& left_margin, int& top_margin, int& width, int& height);
|
||||
bool has_rawMask(int idx);
|
||||
void get_rawMask(int idx, int& top, int& left, int& bottom, int& right);
|
||||
int get_BlackLevel(int idx, int iso_speed);
|
||||
int get_WhiteLevel(int idx, int iso_speed, float fnumber);
|
||||
void update_Levels(const CameraConst *other);
|
||||
|
@@ -61,7 +61,13 @@ Examples:
|
||||
// ColorMatrix with D65 Calibration Illuminant, in dcraw format
|
||||
"dcraw_matrix": [ 7530, -1942, -255, -4318, 11390, 3362, -926, 1694, 7649 ],
|
||||
// black and white level same for all colors at all ISOs
|
||||
"ranges": { "black": 10, "white": 1000 }
|
||||
"ranges": { "black": 10, "white": 1000 },
|
||||
// crop away masked sensor borders, 10 pixels left, 20 pixels top, resulting image width/height 4000x3000
|
||||
// instead of width/height you can write a negative number which specifies how much of right/bottom border
|
||||
// that should be removed
|
||||
"raw_crop": [ 10, 20, 4000, 3000 ],
|
||||
// same as MaskedAreas DNG tag, used for black level measuring here two areas defined
|
||||
"masked_areas": [ 51, 2, 3804, 156, 51, 5794, 3804, 5792 ],
|
||||
},
|
||||
|
||||
{
|
||||
@@ -500,6 +506,8 @@ Quality X: unknown, ie we knowing to little about the camera properties to know
|
||||
{
|
||||
"make_model": "DummyMake DummyModel",
|
||||
"dcraw_matrix": [ 7530,-1942,-255,-4318,11390,3362,-926,1694,7649 ],
|
||||
"raw_crop": [ 10, 20, 4000, 3000 ],
|
||||
"masked_areas": [ 51, 2, 3804, 156, 51, 5794, 3804, 5792 ],
|
||||
"ranges": {
|
||||
"aperture_scaling": [
|
||||
{ "aperture": 1.2, "scale_factor": 1.1 },
|
||||
@@ -507,6 +515,7 @@ Quality X: unknown, ie we knowing to little about the camera properties to know
|
||||
],
|
||||
"black": [
|
||||
{ "iso": 100 , "levels": [ 10, 20, 10, 20 ] },
|
||||
{ "iso": [100, 200] , "levels": [ 30, 40, 30 ] },
|
||||
{ "iso": 3200, "levels": [ 50, 60, 50, 60 ] }
|
||||
],
|
||||
"white": [
|
||||
|
@@ -232,11 +232,41 @@ int RawImage::loadRaw (bool loadData, bool closeFile)
|
||||
fseek (ifp, data_offset, SEEK_SET);
|
||||
(this->*load_raw)();
|
||||
|
||||
if (raw_image) {
|
||||
crop_masked_pixels();
|
||||
free (raw_image);
|
||||
raw_image=NULL;
|
||||
}
|
||||
CameraConstantsStore* ccs = CameraConstantsStore::getInstance();
|
||||
CameraConst *cc = ccs->get(make, model);
|
||||
|
||||
if (raw_image) {
|
||||
if (cc && cc->has_rawCrop()) {
|
||||
int lm, tm, w, h;
|
||||
cc->get_rawCrop(lm, tm, w, h);
|
||||
left_margin = lm;
|
||||
top_margin = tm;
|
||||
if (w < 0) {
|
||||
iwidth += w;
|
||||
iwidth -= left_margin;
|
||||
width += w;
|
||||
width -= left_margin;
|
||||
} else if (w > 0) {
|
||||
iwidth = width = w;
|
||||
}
|
||||
if (h < 0) {
|
||||
iheight += h;
|
||||
iheight -= top_margin;
|
||||
height += h;
|
||||
height -= top_margin;
|
||||
} else if (h > 0) {
|
||||
iheight = height = h;
|
||||
}
|
||||
}
|
||||
if (cc && cc->has_rawMask(0)) {
|
||||
for (int i = 0; i < 8 && cc->has_rawMask(i); i++) {
|
||||
cc->get_rawMask(i, mask[i][0], mask[i][1], mask[i][2], mask[i][3]);
|
||||
}
|
||||
}
|
||||
crop_masked_pixels();
|
||||
free (raw_image);
|
||||
raw_image=NULL;
|
||||
}
|
||||
|
||||
// Load embedded profile
|
||||
if (profile_length) {
|
||||
@@ -257,8 +287,6 @@ int RawImage::loadRaw (bool loadData, bool closeFile)
|
||||
*/
|
||||
int black_c4[4] = { -1, -1, -1, -1 };
|
||||
|
||||
CameraConstantsStore* ccs = CameraConstantsStore::getInstance();
|
||||
CameraConst *cc = ccs->get(make, model);
|
||||
bool white_from_cc = false;
|
||||
bool black_from_cc = false;
|
||||
if (cc) {
|
||||
@@ -296,6 +324,7 @@ int RawImage::loadRaw (bool loadData, bool closeFile)
|
||||
black_from_cc ? "provided by camconst.json" : "provided by dcraw");
|
||||
printf("white levels: R:%d G1:%d B:%d G2:%d (%s)\n", get_white(0), get_white(1), get_white(2), get_white(3),
|
||||
white_from_cc ? "provided by camconst.json" : "provided by dcraw");
|
||||
printf("raw crop: %d %d %d %d (provided by %s)\n", left_margin, top_margin, iwidth, iheight, (cc && cc->has_rawCrop()) ? "camconst.json" : "dcraw");
|
||||
printf("color matrix provided by %s\n", (cc && cc->has_dcrawMatrix()) ? "camconst.json" : "dcraw");
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user