Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Image Decoder to have consistent behavior across backends #2843

Closed
wants to merge 6 commits into from

Conversation

JanuszL
Copy link
Contributor

@JanuszL JanuszL commented Apr 6, 2021

Why we need this PR?

Pick one, remove the rest

  • Rework Image decoder behavior to be consistent across backends

What happened in this PR?

Fill relevant points, put NA otherwise. Replace anything inside []

  • What solution was applied:
    Consistent handling of ANY_DATA image type. TIFFs support any number of channels, the rest of the formats are limited to 1-channel and 3-channel
    Added tests to check that mixed and CPU backends produce the same results.
  • Affected modules and functionalities:
    nvjpeg_decoder_decoupled_api.h
    image decoder tests
  • Key points relevant for the review:
    NA
  • Validation and testing:
    new tests are added
  • Documentation (including examples):
    NA

Relates to #2842

JIRA TASK: [DALI-1948]

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [2240196]: BUILD STARTED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [2240196]: BUILD FAILED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [2242201]: BUILD STARTED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [2242201]: BUILD FAILED

Comment on lines 30 to 31
DALI_ENFORCE(image_type != DALI_ANY_DATA, "Host decoder doesn't support ANY_DATA image type for "
"this image");
Copy link
Contributor

Choose a reason for hiding this comment

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

Why?

Copy link
Contributor

Choose a reason for hiding this comment

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

You can pass IMREAD_ANYCOLOR and/or IMREAD_UNCHANGED to imdecode to keep the original number of channels.

Copy link
Contributor

@mzient mzient Apr 7, 2021

Choose a reason for hiding this comment

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

Checked: neither of these would force OpenCV to keep original color format in JPEGs.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This PR is to make sure we are at least consistent and fail instead of providing random results or out-of-bound memory access.
Supporting multichannel image formats is a full-fledged feature, not a quick fix.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't know why it would result in out-of-bounds access. Just throwing away support for alpha in PNGs (which OpenCV does support) seems quite wasteful.

@JanuszL JanuszL changed the title Add a proper check for the requested number of channels [WIP] Add a proper check for the requested number of channels Apr 7, 2021
batch_size=batch_size_alias_test, N_iterations=10,
eps = 1e-03)

def test_image_decoder_multi_fail():
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This fails for CUDA 10 as we don't have nvJPEG2000 there, and we just use host fallback that doesn't apply enforce, but just converts the image to RGB.

Copy link
Contributor

Choose a reason for hiding this comment

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

Fixed.

JanuszL and others added 5 commits April 8, 2021 18:29
- adds a check inside the decoder if the requested image format matches
  the underlying image
- adds check only or JPEG2000 as in case of JPEG only RGB images are supported,
  for the host fallback DALI always convert to the expected format if requested

Signed-off-by: Janusz Lisiecki <jlisiecki@nvidia.com>
…g. RGBA) to RGB.

Signed-off-by: Joaquin Anton <janton@nvidia.com>
Signed-off-by: Joaquin Anton <janton@nvidia.com>
Signed-off-by: Joaquin Anton <janton@nvidia.com>
Signed-off-by: Joaquin Anton <janton@nvidia.com>
@jantonguirao jantonguirao changed the title [WIP] Add a proper check for the requested number of channels Image Decoder to have consistent behavior across backends Apr 8, 2021
Comment on lines 29 to 32
const auto shape = PeekShapeImpl(encoded_buffer, length);
if (image_type == DALI_ANY_DATA)
image_type = shape[2] == 1 ? DALI_GRAY : DALI_RGB;
const auto C = IsColor(image_type) ? 3 : 1;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Suggested change
const auto shape = PeekShapeImpl(encoded_buffer, length);
if (image_type == DALI_ANY_DATA)
image_type = shape[2] == 1 ? DALI_GRAY : DALI_RGB;
const auto C = IsColor(image_type) ? 3 : 1;
if (image_type == DALI_ANY_DATA) {
const auto shape = PeekShapeImpl(encoded_buffer, length);
image_type = shape[2] == 1 ? DALI_GRAY : DALI_RGB;
}
const auto C = IsColor(image_type) ? 3 : 1;

Peek shape is not free.

Comment on lines 41 to 42
assert(shape[0] == H);
assert(shape[1] == W);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe we do not need that.

auto r = input[tid];
auto g = input[tid + comp_size];
auto b = input[tid + 2 * comp_size];
output[tid] = 0.299f * r + 0.587f * g + 0.114f * b;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can't we just use rgb_to_y ?

files = glob.glob(os.path.join(test_data_root, "db/single/multichannel/tiff_multichannel") + "/*.tif*")
_testimpl_image_decoder_consistency_multichannel(files)

def test_image_decoder_consistenty_multichannel_png_with_alpha():
Copy link
Contributor Author

@JanuszL JanuszL Apr 8, 2021

Choose a reason for hiding this comment

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

It is png and jp2 with alpha.

Comment on lines 164 to 178
def test_image_decoder_consistenty_jpeg():
files = glob.glob(os.path.join(test_data_root, "db/single/jpeg/113") + "/*.jpg*")
_testimpl_image_decoder_consistency(files)

def test_image_decoder_consistenty_jpeg2k():
files = glob.glob(os.path.join(test_data_root, "db/single/jpeg2k/0") + "/*.jp2*")
_testimpl_image_decoder_consistency(files)

def test_image_decoder_consistenty_bmp():
files = glob.glob(os.path.join(test_data_root, "db/single/bmp/0") + "/*.bmp*")
_testimpl_image_decoder_consistency(files)

def test_image_decoder_consistenty_png():
files = glob.glob(os.path.join(test_data_root, "db/single/png/0") + "/*.png*")
_testimpl_image_decoder_consistency(files)
Copy link
Contributor Author

@JanuszL JanuszL Apr 8, 2021

Choose a reason for hiding this comment

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

Suggested change
def test_image_decoder_consistenty_jpeg():
files = glob.glob(os.path.join(test_data_root, "db/single/jpeg/113") + "/*.jpg*")
_testimpl_image_decoder_consistency(files)
def test_image_decoder_consistenty_jpeg2k():
files = glob.glob(os.path.join(test_data_root, "db/single/jpeg2k/0") + "/*.jp2*")
_testimpl_image_decoder_consistency(files)
def test_image_decoder_consistenty_bmp():
files = glob.glob(os.path.join(test_data_root, "db/single/bmp/0") + "/*.bmp*")
_testimpl_image_decoder_consistency(files)
def test_image_decoder_consistenty_png():
files = glob.glob(os.path.join(test_data_root, "db/single/png/0") + "/*.png*")
_testimpl_image_decoder_consistency(files)
def test_image_decoder_consistency():
for img_type in test_good_path:
data_path = os.path.join(test_data_root, good_path, img_type)
files = glob.glob(data_path + "/*/*.[!txt]*")
yield _testimpl_image_decoder_consistency, files[0:10]

Signed-off-by: Joaquin Anton <janton@nvidia.com>
_testimpl_image_decoder_consistency_multichannel(files)

def _testimpl_image_decoder_consistency(img_format, img_out_type):
files = get_img_files(os.path.join(test_data_root, good_path, img_format))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Does it make sense to limit the files to 10 or so?
Or it is better to run the test for all of them?

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't see the need of limiting the files we send to the reader, we'll test more or less files depending on the batch size and number of iterations

Copy link
Contributor Author

@JanuszL JanuszL left a comment

Choose a reason for hiding this comment

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

LGTM but I cannot approve as this PR is based on my own.

@jantonguirao
Copy link
Contributor

Closed in favor of #2867

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants