@brief: preprocess the image for Qwen2VL model @note: Converts uint8 image to BF16 format, data is already in (3, H, W) CHW layout @param: image: the image to preprocess (already in CHW format) @return: the preprocessed image in BF16 format
| 163 | ///@param: image: the image to preprocess (already in CHW format) |
| 164 | ///@return: the preprocessed image in BF16 format |
| 165 | void Qwen2VL::preprocess_image(qwen2vl_image_t& image, std::vector<bf16> &pixel_values) { |
| 166 | const int width = image.width; |
| 167 | const int height = image.height; |
| 168 | const int channels = 3; // RGB |
| 169 | int resized_height; |
| 170 | int resized_width; |
| 171 | // do the automatically resizing in here |
| 172 | smart_resize( |
| 173 | height, width, |
| 174 | resized_height, resized_width, |
| 175 | QWEN2_PATCH_SIZE * QWEN2_IMAGE_MERGE_SIZE, |
| 176 | QWEN2_SHORTEST_EDGE, |
| 177 | QWEN2_LONGEST_EDGE |
| 178 | ); |
| 179 | // std::cout << "resized_height "<< resized_height << " resized_width " << resized_width <<std::endl; |
| 180 | |
| 181 | // Use non-optimized path for consistent results across platforms |
| 182 | auto resize_image = imgproc::avx512::resize_bicubic_antialias_rgb_planar_avx512( |
| 183 | image._data.data(), width, height, resized_width, resized_height, true |
| 184 | ); |
| 185 | |
| 186 | // Padding Logic (Align to Window Size) |
| 187 | const int target_window_size = 112; |
| 188 | const int vit_merger_window_size = target_window_size / QWEN2_IMAGE_MERGE_SIZE / QWEN2_PATCH_SIZE; |
| 189 | const int align_unit = QWEN2_PATCH_SIZE * QWEN2_IMAGE_MERGE_SIZE * vit_merger_window_size; |
| 190 | |
| 191 | int pad_h = (align_unit - (resized_height % align_unit)) % align_unit; |
| 192 | int pad_w = (align_unit - (resized_width % align_unit)) % align_unit; |
| 193 | |
| 194 | if (pad_h > 0 || pad_w > 0) { |
| 195 | const int padded_width = resized_width + pad_w; |
| 196 | const int padded_height = resized_height + pad_h; |
| 197 | |
| 198 | const size_t src_plane_size = static_cast<size_t>(resized_width) * resized_height; |
| 199 | const size_t dst_plane_size = static_cast<size_t>(padded_width) * padded_height; |
| 200 | |
| 201 | resize_image.resize(dst_plane_size * channels); |
| 202 | |
| 203 | // Expand each plane in-place from back to front to avoid extra temporary allocations. |
| 204 | for (int c = channels - 1; c >= 0; --c) { |
| 205 | uint8_t* src_plane = resize_image.data() + static_cast<size_t>(c) * src_plane_size; |
| 206 | uint8_t* dst_plane = resize_image.data() + static_cast<size_t>(c) * dst_plane_size; |
| 207 | |
| 208 | for (int y = resized_height - 1; y >= 0; --y) { |
| 209 | std::memmove(dst_plane + static_cast<size_t>(y) * padded_width, |
| 210 | src_plane + static_cast<size_t>(y) * resized_width, |
| 211 | resized_width); |
| 212 | if (pad_w > 0) { |
| 213 | std::memset(dst_plane + static_cast<size_t>(y) * padded_width + resized_width, 0, pad_w); |
| 214 | } |
| 215 | } |
| 216 | |
| 217 | if (pad_h > 0) { |
| 218 | std::memset(dst_plane + static_cast<size_t>(resized_height) * padded_width, |
| 219 | 0, |
| 220 | static_cast<size_t>(pad_h) * padded_width); |
| 221 | } |
| 222 | } |
nothing calls this directly
no test coverage detected