Implements Equalize function from PIL using TF ops.
(image)
| 363 | |
| 364 | |
| 365 | def equalize(image): |
| 366 | """Implements Equalize function from PIL using TF ops.""" |
| 367 | def scale_channel(im, c): |
| 368 | """Scale the data in the channel to implement equalize.""" |
| 369 | im = tf.cast(im[:, :, c], tf.int32) |
| 370 | # Compute the histogram of the image channel. |
| 371 | histo = tf.histogram_fixed_width(im, [0, 255], nbins=256) |
| 372 | |
| 373 | # For the purposes of computing the step, filter out the nonzeros. |
| 374 | nonzero = tf.where(tf.not_equal(histo, 0)) |
| 375 | nonzero_histo = tf.reshape(tf.gather(histo, nonzero), [-1]) |
| 376 | step = (tf.reduce_sum(nonzero_histo) - nonzero_histo[-1]) // 255 |
| 377 | |
| 378 | def build_lut(histo, step): |
| 379 | # Compute the cumulative sum, shifting by step // 2 |
| 380 | # and then normalization by step. |
| 381 | lut = (tf.cumsum(histo) + (step // 2)) // step |
| 382 | # Shift lut, prepending with 0. |
| 383 | lut = tf.concat([[0], lut[:-1]], 0) |
| 384 | # Clip the counts to be in range. This is done |
| 385 | # in the C code for image.point. |
| 386 | return tf.clip_by_value(lut, 0, 255) |
| 387 | |
| 388 | # If step is zero, return the original image. Otherwise, build |
| 389 | # lut from the full histogram and step and then index from it. |
| 390 | result = tf.cond(tf.equal(step, 0), |
| 391 | lambda: im, |
| 392 | lambda: tf.gather(build_lut(histo, step), im)) |
| 393 | |
| 394 | return tf.cast(result, tf.uint8) |
| 395 | |
| 396 | # Assumes RGB for now. Scales each channel independently |
| 397 | # and then stacks the result. |
| 398 | s1 = scale_channel(image, 0) |
| 399 | s2 = scale_channel(image, 1) |
| 400 | s3 = scale_channel(image, 2) |
| 401 | image = tf.stack([s1, s2, s3], 2) |
| 402 | return image |
| 403 | |
| 404 | |
| 405 | def invert(image): |
nothing calls this directly
no test coverage detected