User facing form to upload image on wordpress

You might want to check out this resource which provides a relatively simple and easy to understand snippet to achieve just that!

Link to the original source from @Matthew Price.

I have pasted the code below for the purpose longevity but please note this is not my code nor am I taking credit for its authorship.

<?php
// if you have this in a file you will need to load "wp-load.php" to get access to WP functions.  If you post to "self" with this code then WordPress is by default loaded
require $_SERVER['DOCUMENT_ROOT'] . "/wp-load.php";
// require two files that are included in the wp-admin but not on the front end.  These give you access to some special functions below.
require $_SERVER['DOCUMENT_ROOT'] . "/wp-admin/includes/file.php";
require $_SERVER['DOCUMENT_ROOT'] . "/wp-admin/includes/image.php";

// required for wp_handle_upload() to upload the file
$upload_overrides = array( 'test_form' => FALSE );

global $current_user;
get_currentuserinfo();
$logged_in_user = $current_user->ID;

// count how many files were uploaded
$count_files = count( $_FILES['files'] );

// load up a variable with the upload direcotry
$uploads = wp_upload_dir();

// foreach file uploaded do the upload
foreach ( range( 0, $count_files ) as $i ) {

    // create an array of the $_FILES for each file
    $file_array = array(
        'name'      => $_FILES['files']['name'][$i],
        'type'      => $_FILES['files']['type'][$i],
        'tmp_name'  => $_FILES['files']['tmp_name'][$i],
        'error'     => $_FILES['files']['error'][$i],
        'size'      => $_FILES['files']['size'][$i],
    );

    // check to see if the file name is not empty
    if ( !empty( $file_array['name'] ) ) {

        // upload the file to the server
        $uploaded_file = wp_handle_upload( $file_array, $upload_overrides );

        // checks the file type and stores in in a variable
        $wp_filetype = wp_check_filetype( basename( $uploaded_file['file'] ), null );  

        // set up the array of arguments for "wp_insert_post();"
        $attachment = array(
            'post_mime_type' => $wp_filetype['type'],
            'post_title' => preg_replace('/\.[^.]+$/', '', basename( $uploaded_file['file'] ) ),
            'post_content' => '',
            'post_author' => $logged_in_user,
            'post_status' => 'inherit',
            'post_type' => 'attachment',
            'post_parent' => $_POST['post_id'],
            'guid' => $uploads['baseurl'] . "https://wordpress.stackexchange.com/" . $file_array['name']
        );

        // insert the attachment post type and get the ID
        $attachment_id = wp_insert_post( $attachment );

        // generate the attachment metadata
        $attach_data = wp_generate_attachment_metadata( $attachment_id, $uploaded_file['file'] );

        // update the attachment metadata
        wp_update_attachment_metadata( $attachment_id,  $attach_data );

                // this is optional and only if you want to.  it is here for reference only.
                // you could set up a separate form to give a specific user the ability to change the post thumbnail
                // set_post_thumbnail( $_POST['post_id', $attachment_id );

    }
}
// setup redirect.  i used the referer so that i can say "file uploaded" in a div if the files query string variable is set.
header("Location: " . $_SERVER['HTTP_REFERER'] . "/?files=uploaded");
?>

An example of the fron end form would be;

<!-- you can place the upload script into your theme folder or in a plugin -->
<form action="/path/to/upload/script/upload.php" method="POST" enctype="multipart/form-data">
    <input type="file" name="files[]" multiple>
    <!-- The following hidden field contains the post id for which you will be uploading images to -->
    <input type="hidden" name="post_id" value="100">
    <input type="submit" class="btn" value="Start Upload »">
</form>

You can adapt it to meet your needs.