add custom field to custom post type

To add a meta box you have to use add_meta_box function which allows us to add meta boxes to the administrative interface.But just adding a meta box doesn’t make it work. You must also have a callback function that prints out the HTML for the edit screen section.

In your case we need that callback function to display an area where user has control of uploading image.

For that we will require to load scripts like media-upload and thickbox. The following example will help you achieve your requirement.

There are comments included to help you understand properly.

    function ks_admin_styles() {
         wp_enqueue_style('thickbox');
    }
    add_action('admin_print_styles', 'ks_admin_styles');        

    function ks_custom_fields(){
        /* Fire our meta box setup function on the post editor screen. */
        add_action( 'load-post.php', 'post_meta_boxes_setup' );
        add_action( 'load-post-new.php', 'post_meta_boxes_setup' );
    }
    add_action('init','ks_custom_fields');

    /* Meta box setup function. */
    function post_meta_boxes_setup() {
        /* Add meta boxes on the 'add_meta_boxes' hook. */
        add_action( 'add_meta_boxes', 'add_post_meta_boxes' );

        /* Save post meta on the 'save_post' hook. */
        add_action( 'save_post', 'save_post_class_meta', 10, 2 );
    }

    /* Create one or more meta boxes to be displayed on the post editor screen. */
    function add_post_meta_boxes() {
        add_meta_box(
            'ks-post-class',      // Unique ID
            esc_html__( 'Post Class', 'example' ),    // Title
            'post_class_meta_box',   // Callback function
            'portfolio',         // Admin page (or post type)
            'side',         // Context
            'default'         // Priority
        );
    }

    /* Display the post meta box. */
    function post_class_meta_box( $object, $box ) { ?>
      <?php wp_nonce_field( basename( __FILE__ ), 'post_class_nonce' ); ?>
      <?php 
        $image = get_post_meta( $object->ID, 'upload_image', true );
      ?>
      <div class="image-upload-block">
        <p>
            <input id="upload_image_<?php echo $i; ?>" type="text" size="100" name="upload_image" class="upload_image" value="https://wordpress.stackexchange.com/questions/192802/<?php echo $image; ?>" />
            <img src="https://wordpress.stackexchange.com/questions/192802/<?php echo $image; ?>" width="50"/>
            <input id="upload_image_button" class="upload_image_button" type="button" value="Upload Image" />
        </p>
        <p>
            <input id="upload_image" type="text" size="100" name="upload_image" class="upload_image" value="" />
            <input id="upload_image_button" class="upload_image_button" type="button" value="Upload Image" />
        </p>
      </div>
    <?php }

    function save_post_class_meta( $post_id, $post ) {
        /* Verify the nonce before proceeding. */
        if ( !isset( $_POST['post_class_nonce'] ) || !wp_verify_nonce( $_POST['post_class_nonce'], basename( __FILE__ ) ) )
            return $post_id;

        /* Get the post type object. */
        $post_type = get_post_type_object( $post->post_type );

        /* Check if the current user has permission to edit the post. */
        if ( !current_user_can( $post_type->cap->edit_post, $post_id ) )
            return $post_id;

        /* Get the posted data and sanitize it for use as an HTML class. */
        $new_meta_value = ( isset( $_POST['upload_image'] ) ?  $_POST['upload_image'] : '' );
        $new_meta_value = serialize($new_meta_value);
        /* Get the meta key. */
        $meta_key = 'upload_image';

        /* Get the meta value of the custom field key. */
        $meta_value = get_post_meta( $post_id, $meta_key, true );

        /* If a new meta value was added and there was no previous value, add it. */
        if ( $new_meta_value && '' == $meta_value ){
            add_post_meta( $post_id, $meta_key, $new_meta_value, true );
        }

        /* If the new meta value does not match the old value, update it. */
        elseif ( $new_meta_value && $new_meta_value != $meta_value ){
            update_post_meta( $post_id, $meta_key, $new_meta_value );
        }

        /* If there is no new meta value but an old value exists, delete it. */
        elseif ( '' == $new_meta_value && $meta_value ){
            delete_post_meta( $post_id, $meta_key, $meta_value );
        }
    }
?>

you can learn more from WordPress Codex for add meta box