Skip to content

Commit ab7b986

Browse files
authored
Merge pull request #1157 from Wanglongzhi2001/master
feat: add adjust_contrast, adjust_hue, combined_non_max_suppression, crop_and_resize image oprs
2 parents a5fdaf4 + 3273cbc commit ab7b986

File tree

3 files changed

+490
-15
lines changed

3 files changed

+490
-15
lines changed

src/TensorFlowNET.Core/APIs/tf.image.cs

Lines changed: 119 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ You may obtain a copy of the License at
1414
limitations under the License.
1515
******************************************************************************/
1616

17+
using OneOf.Types;
18+
using System;
19+
using System.Buffers.Text;
20+
using Tensorflow.Contexts;
1721
using static Tensorflow.Binding;
1822

1923
namespace Tensorflow
@@ -162,17 +166,108 @@ public Tensor ssim_multiscale(Tensor img1, Tensor img2, float max_val, float[] p
162166
public Tensor sobel_edges(Tensor image)
163167
=> image_ops_impl.sobel_edges(image);
164168

165-
public Tensor decode_jpeg(Tensor contents,
166-
int channels = 0,
167-
int ratio = 1,
168-
bool fancy_upscaling = true,
169-
bool try_recover_truncated = false,
170-
int acceptable_fraction = 1,
171-
string dct_method = "",
172-
string name = null)
173-
=> gen_image_ops.decode_jpeg(contents, channels: channels, ratio: ratio,
174-
fancy_upscaling: fancy_upscaling, try_recover_truncated: try_recover_truncated,
175-
acceptable_fraction: acceptable_fraction, dct_method: dct_method);
169+
/// <summary>
170+
/// Adjust contrast of RGB or grayscale images.
171+
/// </summary>
172+
/// <param name="images">Images to adjust. At least 3-D.</param>
173+
/// <param name="contrast_factor"></param>
174+
/// <param name="name">A float multiplier for adjusting contrast.</param>
175+
/// <returns>The contrast-adjusted image or images.</returns>
176+
public Tensor adjust_contrast(Tensor images, float contrast_factor, string name = null)
177+
=> gen_image_ops.adjust_contrastv2(images, contrast_factor, name);
178+
179+
/// <summary>
180+
/// Adjust hue of RGB images.
181+
/// </summary>
182+
/// <param name="images">RGB image or images. The size of the last dimension must be 3.</param>
183+
/// <param name="delta">float. How much to add to the hue channel.</param>
184+
/// <param name="name">A name for this operation (optional).</param>
185+
/// <returns>Adjusted image(s), same shape and DType as `image`.</returns>
186+
/// <exception cref="ValueError">if `delta` is not in the interval of `[-1, 1]`.</exception>
187+
public Tensor adjust_hue(Tensor images, float delta, string name = null)
188+
{
189+
if (tf.Context.executing_eagerly())
190+
{
191+
if (delta < -1f || delta > 1f)
192+
throw new ValueError("delta must be in the interval [-1, 1]");
193+
}
194+
return gen_image_ops.adjust_hue(images, delta, name: name);
195+
}
196+
197+
/// <summary>
198+
/// Adjust saturation of RGB images.
199+
/// </summary>
200+
/// <param name="image">RGB image or images. The size of the last dimension must be 3.</param>
201+
/// <param name="saturation_factor">float. Factor to multiply the saturation by.</param>
202+
/// <param name="name">A name for this operation (optional).</param>
203+
/// <returns>Adjusted image(s), same shape and DType as `image`.</returns>
204+
public Tensor adjust_saturation(Tensor image, float saturation_factor, string name = null)
205+
=> gen_image_ops.adjust_saturation(image, saturation_factor, name);
206+
207+
/// <summary>
208+
/// Greedily selects a subset of bounding boxes in descending order of score.
209+
/// </summary>
210+
/// <param name="boxes">
211+
/// A 4-D float `Tensor` of shape `[batch_size, num_boxes, q, 4]`. If `q`
212+
/// is 1 then same boxes are used for all classes otherwise, if `q` is equal
213+
/// to number of classes, class-specific boxes are used.
214+
/// </param>
215+
/// <param name="scores">
216+
/// A 3-D float `Tensor` of shape `[batch_size, num_boxes, num_classes]`
217+
/// representing a single score corresponding to each box(each row of boxes).
218+
/// </param>
219+
/// <param name="max_output_size_per_class">
220+
/// A scalar integer `Tensor` representing the
221+
/// maximum number of boxes to be selected by non-max suppression per class
222+
/// </param>
223+
/// <param name="max_total_size">
224+
/// A int32 scalar representing maximum number of boxes retained
225+
/// over all classes.Note that setting this value to a large number may
226+
/// result in OOM error depending on the system workload.
227+
/// </param>
228+
/// <param name="iou_threshold">
229+
/// A float representing the threshold for deciding whether boxes
230+
/// overlap too much with respect to IOU.
231+
/// </param>
232+
/// <param name="score_threshold">
233+
/// A float representing the threshold for deciding when to
234+
/// remove boxes based on score.
235+
/// </param>
236+
/// <param name="pad_per_class">
237+
/// If false, the output nmsed boxes, scores and classes are
238+
/// padded/clipped to `max_total_size`. If true, the output nmsed boxes, scores and classes are padded to be of length `max_size_per_class`*`num_classes`,
239+
/// unless it exceeds `max_total_size` in which case it is clipped to `max_total_size`. Defaults to false.
240+
/// </param>
241+
/// <param name="clip_boxes">
242+
/// If true, the coordinates of output nmsed boxes will be clipped
243+
/// to[0, 1]. If false, output the box coordinates as it is. Defaults to true.
244+
/// </param>
245+
/// <returns>
246+
/// 'nmsed_boxes': A [batch_size, max_detections, 4] float32 tensor containing the non-max suppressed boxes.
247+
/// 'nmsed_scores': A [batch_size, max_detections] float32 tensor containing the scores for the boxes.
248+
/// 'nmsed_classes': A [batch_size, max_detections] float32 tensor containing the class for boxes.
249+
/// 'valid_detections': A [batch_size] int32 tensor indicating the number of
250+
/// valid detections per batch item. Only the top valid_detections[i] entries
251+
/// in nms_boxes[i], nms_scores[i] and nms_class[i] are valid. The rest of the
252+
/// entries are zero paddings.
253+
/// </returns>
254+
public (Tensor, Tensor, Tensor, Tensor) combined_non_max_suppression(
255+
Tensor boxes,
256+
Tensor scores,
257+
int max_output_size_per_class,
258+
int max_total_size,
259+
float iou_threshold,
260+
float score_threshold,
261+
bool pad_per_class = false,
262+
bool clip_boxes = true)
263+
{
264+
var iou_threshold_t = ops.convert_to_tensor(iou_threshold, TF_DataType.TF_FLOAT, name: "iou_threshold");
265+
var score_threshold_t = ops.convert_to_tensor(score_threshold, TF_DataType.TF_FLOAT, name: "score_threshold");
266+
var max_total_size_t = ops.convert_to_tensor(max_total_size);
267+
var max_output_size_per_class_t = ops.convert_to_tensor(max_output_size_per_class);
268+
return gen_image_ops.combined_non_max_suppression(boxes, scores, max_output_size_per_class_t, max_total_size_t,
269+
iou_threshold_t, score_threshold_t, pad_per_class, clip_boxes);
270+
}
176271

177272
/// <summary>
178273
/// Extracts crops from the input image tensor and resizes them using bilinear sampling or nearest neighbor sampling (possibly with aspect ratio change) to a common output size specified by crop_size. This is more general than the crop_to_bounding_box op which extracts a fixed size slice from the input image and does not allow resizing or aspect ratio change.
@@ -187,7 +282,19 @@ public Tensor decode_jpeg(Tensor contents,
187282
/// <param name="name">A name for the operation (optional).</param>
188283
/// <returns>A 4-D tensor of shape [num_boxes, crop_height, crop_width, depth].</returns>
189284
public Tensor crop_and_resize(Tensor image, Tensor boxes, Tensor box_ind, Tensor crop_size, string method = "bilinear", float extrapolation_value = 0f, string name = null) =>
190-
image_ops_impl.crop_and_resize(image, boxes, box_ind, crop_size, method, extrapolation_value, name);
285+
gen_image_ops.crop_and_resize(image, boxes, box_ind, crop_size, method, extrapolation_value, name);
286+
287+
public Tensor decode_jpeg(Tensor contents,
288+
int channels = 0,
289+
int ratio = 1,
290+
bool fancy_upscaling = true,
291+
bool try_recover_truncated = false,
292+
int acceptable_fraction = 1,
293+
string dct_method = "",
294+
string name = null)
295+
=> gen_image_ops.decode_jpeg(contents, channels: channels, ratio: ratio,
296+
fancy_upscaling: fancy_upscaling, try_recover_truncated: try_recover_truncated,
297+
acceptable_fraction: acceptable_fraction, dct_method: dct_method);
191298

192299
public Tensor extract_glimpse(Tensor input, Tensor size, Tensor offsets, bool centered = true, bool normalized = true,
193300
bool uniform_noise = true, string name = null)

0 commit comments

Comments
 (0)