Given an image file name, read in the data, try to decode it as an image, resize it to the requested size, and then scale the values as desired.
| 114 | // Given an image file name, read in the data, try to decode it as an image, |
| 115 | // resize it to the requested size, and then scale the values as desired. |
| 116 | Status ReadTensorFromImageFile(const string& file_name, const int input_height, |
| 117 | const int input_width, const float input_mean, |
| 118 | const float input_std, |
| 119 | std::vector<Tensor>* out_tensors) { |
| 120 | auto root = tensorflow::Scope::NewRootScope(); |
| 121 | using namespace ::tensorflow::ops; // NOLINT(build/namespaces) |
| 122 | |
| 123 | string input_name = "file_reader"; |
| 124 | string output_name = "normalized"; |
| 125 | |
| 126 | // read file_name into a tensor named input |
| 127 | Tensor input(tensorflow::DT_STRING, tensorflow::TensorShape()); |
| 128 | TF_RETURN_IF_ERROR( |
| 129 | ReadEntireFile(tensorflow::Env::Default(), file_name, &input)); |
| 130 | |
| 131 | // use a placeholder to read input data |
| 132 | auto file_reader = |
| 133 | Placeholder(root.WithOpName("input"), tensorflow::DataType::DT_STRING); |
| 134 | |
| 135 | std::vector<std::pair<string, tensorflow::Tensor>> inputs = { |
| 136 | {"input", input}, |
| 137 | }; |
| 138 | |
| 139 | // Now try to figure out what kind of file it is and decode it. |
| 140 | const int wanted_channels = 3; |
| 141 | tensorflow::Output image_reader; |
| 142 | if (tensorflow::str_util::EndsWith(file_name, ".png")) { |
| 143 | image_reader = DecodePng(root.WithOpName("png_reader"), file_reader, |
| 144 | DecodePng::Channels(wanted_channels)); |
| 145 | } else if (tensorflow::str_util::EndsWith(file_name, ".gif")) { |
| 146 | // gif decoder returns 4-D tensor, remove the first dim |
| 147 | image_reader = |
| 148 | Squeeze(root.WithOpName("squeeze_first_dim"), |
| 149 | DecodeGif(root.WithOpName("gif_reader"), file_reader)); |
| 150 | } else if (tensorflow::str_util::EndsWith(file_name, ".bmp")) { |
| 151 | image_reader = DecodeBmp(root.WithOpName("bmp_reader"), file_reader); |
| 152 | } else { |
| 153 | // Assume if it's neither a PNG nor a GIF then it must be a JPEG. |
| 154 | image_reader = DecodeJpeg(root.WithOpName("jpeg_reader"), file_reader, |
| 155 | DecodeJpeg::Channels(wanted_channels)); |
| 156 | } |
| 157 | // Now cast the image data to float so we can do normal math on it. |
| 158 | auto float_caster = |
| 159 | Cast(root.WithOpName("float_caster"), image_reader, tensorflow::DT_FLOAT); |
| 160 | // The convention for image ops in TensorFlow is that all images are expected |
| 161 | // to be in batches, so that they're four-dimensional arrays with indices of |
| 162 | // [batch, height, width, channel]. Because we only have a single image, we |
| 163 | // have to add a batch dimension of 1 to the start with ExpandDims(). |
| 164 | auto dims_expander = ExpandDims(root, float_caster, 0); |
| 165 | // Bilinearly resize the image to fit the required dimensions. |
| 166 | auto resized = ResizeBilinear( |
| 167 | root, dims_expander, |
| 168 | Const(root.WithOpName("size"), {input_height, input_width})); |
| 169 | // Subtract the mean and divide by the scale. |
| 170 | Div(root.WithOpName(output_name), Sub(root, resized, {input_mean}), |
| 171 | {input_std}); |
| 172 | |
| 173 | // This runs the GraphDef network definition that we've just constructed, and |
no test coverage detected