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

Add smart image cropping with Computer Vision #149

Merged
merged 26 commits into from
Feb 18, 2020

Conversation

johnwatkins0
Copy link
Member

This PR introduces smart image cropping provided by Computer Vision.

It would resolve #112. I think #135 could integrate smart cropping without much additional effort.

Description of the Change

Sites are opted into the service through a checkbox on the image processing settings page. As an image is uploaded, each intermediate image size with cropping generates a request to the external service. If a cropped image is successfully returned, that image is saved and added to the image metadata in place of the version generated by WordPress (which remains in the file system).

Screen Shot 2019-10-13 at 8 10 05 PM

Screen Shot 2019-10-13 at 8 11 07 PM

Screen Shot 2019-10-13 at 8 11 51 PM

Alternate Designs

  • I considered deleting the original non-smart-cropped file when Computer Vision successfully returns a cropped image. This would save server space. I'm still on the fence about it.
  • I also considered adding a checkbox group on the settings page allowing the feature to be opted into on the basis of specific image sizes, but this felt too complex. I did introduce a couple of filters that could be used to turn off smart-cropping specific image sizes.

Benefits

Thumbnails are nicely cropped around faces and other focal points.

Possible Drawbacks

A separate request needs to be made for each cropped image size. Only one core image size is cropped by default, but themes/plugins can register any number of cropped sizes. I think at some point the external requests around image processing are going to need to be done asynchronously rather than during pageload execution.

Verification Process

This only works on a publicly accessible site.

  1. On the "Image Processing" Classifai settings page, with credentials in place, check the "Enable smart cropping" checkbox.
  2. Upload a file to the media library. Useful files for testing are large portraits of people or similar photos in which the main focal point is significantly off center. The 150x150 thumbnail size is good for testing.
  3. Upload the same file with the "Enable smart cropping" checkbox unchecked, and note the difference.
  4. You might need to try a few files before you see a big difference.

Checklist:

  • I have read the CONTRIBUTING document.
  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my change.
  • All new and existing tests passed.

*
* @return int
*/
function computer_vision_max_filesize() {
Copy link
Member Author

@johnwatkins0 johnwatkins0 Oct 14, 2019

Choose a reason for hiding this comment

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

Moved these functions out of the ComputerVision class because they're now called from multiple places and don't use ComputerVision class state.

* @param string The request URL with query args added.
* @param array Array containing the image height and width.
*/
do_action( 'classifai_smart_cropping_unsuccessful_response', $response, $url, $data );
Copy link
Member Author

Choose a reason for hiding this comment

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

Can use the failed response for #143

@johnwatkins0 johnwatkins0 added this to the 1.5.0 milestone Oct 14, 2019
@johnwatkins0 johnwatkins0 added the type:enhancement New feature or request. label Oct 14, 2019
@johnwatkins0 johnwatkins0 self-assigned this Oct 14, 2019
@jeffpaul
Copy link
Member

In regards to Alternate Designs 1: "I considered deleting the original non-smart-cropped file when Computer Vision successfully returns a cropped image. This would save server space. I'm still on the fence about it.", I think I'm on the side of the fence of deleting the original non-smart-cropped file as I'm not sure there would be an easy way for a site owner to swap that back into place of the smart-cropped file and its not as though we're deleting the main source image itself.

@jeffpaul
Copy link
Member

In regards to Alternate Designs 2: "I also considered adding a checkbox group on the settings page allowing the feature to be opted into on the basis of specific image sizes, but this felt too complex. I did introduce a couple of filters that could be used to turn off smart-cropping specific image sizes.", I agree with the lesser complexity of the single checkbox on the settings page and that providing filters seems the better route for flexibility.

@rickalee
Copy link

Hi team,

Did some initial tests with Azure Blob Storage to ensure that images could be smart cropped even when offloaded to external service.

Good news: Initial images under 4MB get smart cropped with Azure Blob Storage

Smart Cropped Camera

If the initial image is over 4MB and needs to go through @filesize to check server side file size it does not get smart cropped.

Not Smart Cropped

cc @johnwatkins0 @jeffpaul

@jeffpaul
Copy link
Member

@rickalee thanks for the testing and feedback... any immediate advice for @johnwatkins0 on tweaks to ensure that images that go through the 4mb file size checks properly get through the smart cropping?

@rickalee
Copy link

Add a check for file_exists when using get_attached_file() if not try wp_get_attachment_url()

Note: With Azure Blob Storage we sometimes proxy example.com/wp-content/uploads/ to Azure Blob so URLs returned from wp_get_attachment_url() may not obviously be Azure Blob. One alternative would be to add a filter to response headers to determine source e.g. x-ms-blob-type: AppendBlob

@johnwatkins0
Copy link
Member Author

johnwatkins0 commented Oct 15, 2019

Thanks, @rickalee . For testing purposes, do you use https://github.com/10up/windows-azure-storage to integrate Azure storage, or something else?

@rickalee
Copy link

@johnwatkins0 That plugin is correct.

@johnwatkins0
Copy link
Member Author

johnwatkins0 commented Oct 16, 2019

Hi, @rickalee, after taking a closer look, I think this can be solved easily. I am weighing a few options, though, and would welcome your thoughts (also CC the reviewers on this PR).

This issue is not with cropping in particular but rather the get_largest_acceptable_image_url function that is now used for two different Computer Vision features (and incidentally was copied into another 10up plugin recently). The function checks the full image size and, if it's too large, walks through the intermediate images and uses the biggest one under the limit.

For cases of remote storage, we need an alternative. Here's what I'm considering:

  1. Don't provide the alternative functionality in this plugin, but provide a filter before get_largest_acceptable_image_url runs. Document the 4MB limit and point plugin/theme developers to the filter (e.g., in a README section specifically addressing remote storage). If the filter returns a file, run the remote request, and if it fails, it fails.
  2. Create an alternative function handling the remote storage case, and provide a filter allowing other theme/plugin developers to specifically opt in at the code level. Opting in would be required.
  3. Do Integrate Watson API for image recognition #2, but with a settings checkbox instead of a filter.
  4. Create the alternative function and find a way to detect remote storage automatically. This could get complicated, because there are so many possible configurations, and multiple popular plugins handling remote storage. If we go with this option, I would suggest (cc @jeffpaul ) that this be a separate issue tackled later.

Thanks!

@rickalee
Copy link

rickalee commented Oct 16, 2019

@johnwatkins0 I think option #1 with filter before get_largest_acceptable_image_url is path of least resistance. Although I'm curious if we should look into 5.3 behavior with Big Images and try and add our hooks after the -2560 crop is generated. Anecdotally big image as is in 5.3 cut original 6.1MB image down to 589kb. https://make.wordpress.org/core/2019/10/09/introducing-handling-of-big-images-in-wordpress-5-3/

@johnwatkins0
Copy link
Member Author

Good idea, @rickalee . I'll see if that can be the solution for 5.3+, with the filter for pre-5.3.

@johnwatkins0
Copy link
Member Author

johnwatkins0 commented Jan 17, 2020

@jeffpaul The need for smart cropping in WordPress has come up in some client conversations lately, including in one fast-moving project with a late-winter launch date. Is there anything I can do to help move this along and maybe get it into the plugin in time?

@jeffpaul
Copy link
Member

@johnwatkins0 I'm hoping that we can finish up some other work here in January so that we shift focus to getting the ClassifAI 1.5 release out in February. Is that timing too slow for what you're hoping for?

@rickalee have you had a chance to review John's latest updates to see if they play well with Azure blob storage such that you can 👍 this PR?

@johnwatkins0
Copy link
Member Author

Thanks, @jeffpaul . February would give us plenty of time.

return false;
}

$data = array(

Choose a reason for hiding this comment

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

We should change it to php 5 array.

@dinhtungdu
Copy link
Contributor

In my test, the PR works great without Azure Storage. But when I use Azure storage, there are still some issues:

  • The thumbnail (150x150) doesn't get smart cropped.
  • The alt doesn't generate with Keep local file unchecked.

return true;
}

/**
* Register the functionality.
*/
public function register() {
add_filter( 'wp_generate_attachment_metadata', [ $this, 'process_image' ], 10, 2 );
add_filter( 'wp_generate_attachment_metadata', [ $this, 'smart_crop_image' ], 10, 2 );
add_filter( 'wp_generate_attachment_metadata', [ $this, 'generate_image_alt_tags' ], 10, 2 );
Copy link
Contributor

Choose a reason for hiding this comment

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

In my test, changing these filters priority to 8 get image tagging and smart cropping work with Azure Storage which hooks to the same filter with priority set to 9.

@jeffpaul
Copy link
Member

@johnwatkins0 are you able to work through the feedback from @Ritesh-patel and @dinhtungdu? If not, I'll see if someone else can help wrap up these so the PR is ready for the v1.5 release.

@johnwatkins0
Copy link
Member Author

@jeffpaul Yes, I can work on it over the next few days.

@johnwatkins0
Copy link
Member Author

Thanks, @dinhtungdu . I have pushed the suggested changes. In my test environment using Azure storage I have uploaded an image and verified that the 150x150 thumb is smart-cropped and that the alt text is generated. Let me know if you find any other issues.

@dinhtungdu dinhtungdu requested review from dinhtungdu and removed request for adamsilverstein January 26, 2020 22:27
Copy link
Contributor

@dinhtungdu dinhtungdu left a comment

Choose a reason for hiding this comment

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

The cropping function works flawlessly locally.

This PR doesn't work with Azure storage because of get_largest_acceptable_image_url(). Because that function exists before this request, we should work on the Azure storage issue in other PR.

@@ -84,18 +115,19 @@ public function get_max_filesize() {
*
* @return mixed
*/
public function process_image( $metadata, $attachment_id ) {
public function generate_image_alt_tags( $metadata, $attachment_id ) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This function is doing both alt and tag generation. IMO, we should

  • Use better name
  • Or even better, split the public method to do only one task.

Copy link
Contributor

Choose a reason for hiding this comment

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

@dinhtungdu just to add some context here. This function handles both items because the results of scan_image return both the captions and tags. The actual creation for tags and alts tags are done by separate functions called by this function. This is a long-winded way of saying that we save another call to the service by doing this all at once.

I'd be for a name change to the function to better reflect what it does though :)

* @param int $max The maximum acceptable size.
* @return string|null The image URL, or null if no acceptable image found.
*/
function get_largest_acceptable_image_url( $full_image, $full_url, $sizes, $max = MB_IN_BYTES ) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This function return NULL with Azure storage enabled and configured. Tested with publicly accessible WP install and newly uploaded images after configuring Azure.

);
$this->assertNull( $url );

remove_filter( 'classifai_computer_vision_max_filesize', $set_1kb_max_filesize );
Copy link
Contributor

Choose a reason for hiding this comment

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

Small nitpick here, if the test fails, this filter won't be removed. I'd recommend moving it up before the $this->assertNull call.

Copy link
Contributor

@ryanwelcher ryanwelcher left a comment

Choose a reason for hiding this comment

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

LGTM!

@ryanwelcher
Copy link
Contributor

@jeffpaul @dinhtungdu I think we can land this feature now and then focus on the Azure Storage integration as an immediate followup. Any concerns with that approach?

@dinhtungdu
Copy link
Contributor

@ryanwelcher No concern, I agree!

@jeffpaul jeffpaul merged commit 0bf9489 into develop Feb 18, 2020
@jeffpaul jeffpaul deleted the feature/smart-image-cropping branch March 5, 2020 01:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type:enhancement New feature or request.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Integrate Azure Computer Vision for smart image cropping
6 participants