Skip to content

Commit 40d1ede

Browse files
committed
Improve black area detection and properly parse IAD1 box
IAD1 contains 4 definitions for rectangles: * crop rectangle * left optical black area rectangle * top optical black area rectangle * active area rectangle This patch parses all IAD1 rectangles and uses them for black areas and crop.
1 parent c32a919 commit 40d1ede

File tree

2 files changed

+119
-32
lines changed

2 files changed

+119
-32
lines changed

src/librawspeed/decoders/Cr3Decoder.cpp

Lines changed: 87 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -417,32 +417,86 @@ IsoMCanonIad1Box::IsoMCanonIad1Box(const AbstractIsoMBox& base)
417417
reserved3 = data.get<uint16_t>();
418418

419419
if (2 == ind) { // ind is 2 for big images
420-
sensorLeftBorder = data.get<uint16_t>();
421-
sensorTopBorder = data.get<uint16_t>();
422-
sensorRightBorder = data.get<uint16_t>();
423-
sensorBottomBorder = data.get<uint16_t>();
424-
data.skipBytes(2 * sizeof(uint16_t));
425-
sensorBlackAreaLeft = data.get<uint16_t>();
426-
data.skipBytes(4 * sizeof(uint16_t));
427-
sensorBlackAreaTop = data.get<uint16_t>();
420+
cropLeftOffset = data.get<uint16_t>();
421+
cropTopOffset = data.get<uint16_t>();
422+
cropRightOffset = data.get<uint16_t>();
423+
cropBottomOffset = data.get<uint16_t>();
424+
425+
leftOpticalBlackLeftOffset = data.get<uint16_t>();
426+
leftOpticalBlackTopOffset = data.get<uint16_t>();
427+
leftOpticalBlackRightOffset = data.get<uint16_t>();
428+
leftOpticalBlackBottomOffset = data.get<uint16_t>();
429+
430+
topOpticalBlackLeftOffset = data.get<uint16_t>();
431+
topOpticalBlackTopOffset = data.get<uint16_t>();
432+
topOpticalBlackRightOffset = data.get<uint16_t>();
433+
topOpticalBlackBottomOffset = data.get<uint16_t>();
434+
435+
activeAreaLeftOffset = data.get<uint16_t>();
436+
activeAreaTopOffset = data.get<uint16_t>();
437+
activeAreaRightOffset = data.get<uint16_t>();
438+
activeAreaBottomOffset = data.get<uint16_t>();
439+
} else {
440+
// We hit a small image box?!
441+
ThrowRDE("IAD1 box contains small image information, but big image expected");
428442
}
429443

430444
writeLog(DEBUG_PRIO_EXTRA,
431445
"IAD1 sensor width: %d, height: %d, crop: %u, %u, %u, %u, black "
432446
"area left: %u, top: %u",
433-
sensorWidth, sensorHeight, sensorLeftBorder, sensorTopBorder,
434-
sensorRightBorder, sensorBottomBorder, sensorBlackAreaLeft,
435-
sensorBlackAreaTop);
447+
sensorWidth, sensorHeight, cropLeftOffset, cropTopOffset,
448+
cropRightOffset, cropBottomOffset, leftOpticalBlackRightOffset,
449+
topOpticalBlackBottomOffset);
436450

437451
// Validate.
438452
operator bool();
439453
}
440454

441455
IsoMCanonIad1Box::operator bool() const {
442-
// No fields yet to validate, IAD1 is unused for decoding.
456+
if(!sensorWidth || !sensorHeight)
457+
ThrowIPE("IAD1 sensor size unknown");
458+
if(!cropRect().isThisInside(sensorRect()))
459+
ThrowIPE("IAD1 crop rect is outside sensor rect");
443460
return true; // OK!
444461
}
445462

463+
iRectangle2D IsoMCanonIad1Box::sensorRect() const {
464+
return iRectangle2D(0, 0, sensorWidth, sensorHeight);
465+
}
466+
467+
iRectangle2D IsoMCanonIad1Box::cropRect() const {
468+
return iRectangle2D(
469+
cropLeftOffset,
470+
cropTopOffset,
471+
(cropRightOffset+1)-cropLeftOffset,
472+
(cropBottomOffset+1)-cropTopOffset);
473+
}
474+
475+
iRectangle2D IsoMCanonIad1Box::leftOpticalBlackRect() const {
476+
return iRectangle2D(
477+
leftOpticalBlackLeftOffset,
478+
leftOpticalBlackTopOffset,
479+
(leftOpticalBlackRightOffset+1)-leftOpticalBlackLeftOffset,
480+
(leftOpticalBlackBottomOffset+1)-leftOpticalBlackTopOffset);
481+
}
482+
483+
iRectangle2D IsoMCanonIad1Box::topOpticalBlackRect() const {
484+
return iRectangle2D(
485+
topOpticalBlackLeftOffset,
486+
topOpticalBlackTopOffset,
487+
(topOpticalBlackRightOffset+1)-topOpticalBlackLeftOffset,
488+
(topOpticalBlackBottomOffset+1)-topOpticalBlackTopOffset);
489+
}
490+
491+
iRectangle2D IsoMCanonIad1Box::activeArea() const {
492+
return iRectangle2D(
493+
activeAreaLeftOffset,
494+
activeAreaTopOffset,
495+
(activeAreaRightOffset+1)-activeAreaLeftOffset,
496+
(activeAreaBottomOffset+1)-activeAreaTopOffset);
497+
}
498+
499+
446500
CanonTimedMetadata::CanonTimedMetadata::Record::Record(ByteStream* bs) {
447501
assert(bs->getByteOrder() == Endianness::little);
448502
auto origPos = bs->getPosition();
@@ -634,23 +688,34 @@ void Cr3Decoder::decodeMetaDataInternal(const CameraMetaData* meta) {
634688
}
635689

636690
setMetaData(meta, camId.make, camId.model, mode, iso);
691+
writeLog(DEBUG_PRIO_EXTRA, "blacklevel for ISO %d is %d", mRaw->metadata.isoSpeed, mRaw->blackLevel);
637692

638-
// IAD1 described sensor constraints
693+
// IAD1 describes sensor constraints
639694
const auto& iad1 = crawBox->CDI1()->IAD1();
640695

641696
if (mRaw->blackAreas.empty()) {
642-
mRaw->blackAreas.push_back(BlackArea(0, iad1->sensorBlackAreaLeft, true));
643-
mRaw->blackAreas.push_back(BlackArea(0, iad1->sensorBlackAreaTop, false));
697+
// IAD1 stores the rectangles for black areas.
698+
auto leftOpticalBlack = iad1->leftOpticalBlackRect();
699+
auto topOpticalBlack = iad1->topOpticalBlackRect();
700+
if(leftOpticalBlack.dim.x >= 12+4) {
701+
// if left optical black has >= 12+4 pixels, we reduce them by 12 as some
702+
// models (EOS RP is known) has white pixels in this area.
703+
// Yes, this is hacky, but IAD1 reports offset=0 which is either wrong or the white pixels
704+
// are a camera bug and must be resolved in software.
705+
leftOpticalBlack.pos.x += 12;
706+
leftOpticalBlack.dim.x -= 12;
707+
}
708+
if(topOpticalBlack.dim.y >= 12+4) {
709+
// Same must be done for horizontal pixels
710+
topOpticalBlack.pos.y += 12;
711+
topOpticalBlack.dim.y -= 12;
712+
}
713+
mRaw->blackAreas.push_back(BlackArea(leftOpticalBlack.pos.x, leftOpticalBlack.dim.x, true));
714+
mRaw->blackAreas.push_back(BlackArea(topOpticalBlack.pos.y, topOpticalBlack.pos.y, false));
644715
}
645716

646717
if (applyCrop) {
647-
// IAD1 sensor parameters always crop one more pixel as needed.
648-
// We add back the missing pixels to match official specifications.
649-
iRectangle2D new_area(iad1->sensorLeftBorder, iad1->sensorTopBorder,
650-
iad1->sensorRightBorder - iad1->sensorLeftBorder + 1,
651-
iad1->sensorBottomBorder - iad1->sensorTopBorder + 1);
652-
653-
mRaw->subFrame(new_area);
718+
mRaw->subFrame(iad1->cropRect());
654719
}
655720
}
656721

src/librawspeed/decoders/Cr3Decoder.h

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -200,18 +200,40 @@ class IsoMCanonIad1Box final : public IsoMFullBox<IsoMBoxCanonTypes::IAD1> {
200200
uint16_t ind; // 0 = small, 1 = big
201201
uint16_t reserved2;
202202
uint16_t reserved3;
203-
// Big image flags (we ignore small flags, not needed for decoding)
204-
uint16_t sensorLeftBorder;
205-
uint16_t sensorTopBorder;
206-
uint16_t sensorRightBorder;
207-
uint16_t sensorBottomBorder;
208-
// followed by more unknown fields
209-
uint16_t sensorBlackAreaLeft;
210-
// followed by more unknown fields
211-
uint16_t sensorBlackAreaTop;
212-
// followed by more unknown fields
203+
204+
// Big image fields (we ignore small image, not needed for decoding)
205+
206+
// Crop rectangle
207+
uint16_t cropLeftOffset;
208+
uint16_t cropTopOffset;
209+
uint16_t cropRightOffset;
210+
uint16_t cropBottomOffset;
211+
212+
// Left optical black rectangle
213+
uint16_t leftOpticalBlackLeftOffset;
214+
uint16_t leftOpticalBlackTopOffset;
215+
uint16_t leftOpticalBlackRightOffset;
216+
uint16_t leftOpticalBlackBottomOffset;
217+
218+
// Top optical black rectangle
219+
uint16_t topOpticalBlackLeftOffset;
220+
uint16_t topOpticalBlackTopOffset;
221+
uint16_t topOpticalBlackRightOffset;
222+
uint16_t topOpticalBlackBottomOffset;
223+
224+
// Active area rectangle
225+
uint16_t activeAreaLeftOffset;
226+
uint16_t activeAreaTopOffset;
227+
uint16_t activeAreaRightOffset;
228+
uint16_t activeAreaBottomOffset;
213229

214230
explicit IsoMCanonIad1Box(const AbstractIsoMBox& base);
231+
232+
iRectangle2D sensorRect() const;
233+
iRectangle2D cropRect() const;
234+
iRectangle2D leftOpticalBlackRect() const;
235+
iRectangle2D topOpticalBlackRect() const;
236+
iRectangle2D activeArea() const;
215237
};
216238

217239

0 commit comments

Comments
 (0)