0
$\begingroup$

I have a PSNR histogram distribution for 6k images and I want to sample a few images from this distribution.

Full PSNR distribution

But as you can see the distribution is right-skewed and the samples will less PSNR values are very few. I want to sample more images with low PSNR values, So random sampling is not helping me. For this reason I wrote a code to sample with bias using a KDE model and I want to know if what I'm doing is correct or if there is a better way to bias my sampling method toward the left of the distribution. my results is shown in the figure below

enter image description here

def kde(x, x_grid, weights, bandwidth=0.2):
    """Kernel Density Estimation with Scipy"""
    kde = gaussian_kde(x, bw_method=bandwidth / x.std(ddof=1), weights=weights)
    return kde.evaluate(x_grid)


def generate_rand_from_pdf(pdf, x_grid, data, sample, skwed=False):
    cdf = np.cumsum(pdf)
    cdf = cdf / cdf[-1]
    if skwed:
        values = skewnorm(50, 0, 1).rvs(sample)
        values = (values-values.min()) / (values.max() -values.min())
    else:
        values = np.random.rand(sample)

    value_bins = np.searchsorted(cdf, values)
    random_from_cdf = x_grid[value_bins]

    data_vbins = np.searchsorted(data, random_from_cdf)
    # rnd_from_samples = data[data_vbins]

    return data_vbins

def sort_twoaArrays(arr1, arr2):
    arr1 = np.vstack((np.arange(arr1.shape[0]), arr1)).T
    arr1.sort(axis=0)
    idxsort = arr1[:, 0]
    arr1 = arr1[:, 1].astype(np.float)
    arr2 = arr2[idxsort.astype(np.int)]
    return arr1, arr2

def unique_arr(data, fnames, idx1):
    data = data.copy()
    fnames = fnames.copy()

    fnames = fnames[idx1]
    fnames, uidx = np.unique(fnames, return_index=True)
    idx1 = idx1[uidx]

    return data[idx1], fnames, idx1


def smaple_from_hist():
    binNum = 50
    samples = 1000
    total_PSNR = np.load('totalPSNR_x8.npy', allow_pickle=True)
    data = total_PSNR[:,2]
    fnames = np.array(total_PSNR[:,3])

    data, fnames = sort_twoaArrays(data, fnames)


    #Create weights on data with less value using max/value and normalized to 1.
    weights = (data.max() / data)**2
    weights = weights / weights.sum()

    # Generate KDS dist and samples.
    x_grid = np.linspace(min(data), max(data), data.shape[0])
    kdepdf = kde(data, x_grid, weights=weights, bandwidth=0.1)
    idx1 = generate_rand_from_pdf(kdepdf, x_grid, data, samples, skwed= False)
    idx2 = generate_rand_from_pdf(kdepdf, x_grid, data, samples, skwed=True)

    kde_samples1, fnames1, idx1 = unique_arr(data, fnames, idx1)
    kde_samples2, fnames2, idx2 = unique_arr(data, fnames, idx2)

    print(kde_samples2.shape)


    # Generate Histogram dist and samples.
    hist, bins = np.histogram(data, bins=binNum)
    bin_midpoints = bins[:-1] + np.diff(bins) / 2
    idx3 = generate_rand_from_pdf(hist, bin_midpoints, data, samples, skwed=True)

    fig = plt.figure(figsize=(15, 7))
    ax1 = fig.add_subplot(1, 2, 1)
    ax2 = fig.add_subplot(1, 2, 2)
    ax1.hist(data, binNum, density=True, alpha=0.5, label='hist')
    ax1.plot(x_grid, kdepdf, color='r', alpha=0.5, lw=3, label='kde')
    ax1.legend()
    ax2.hist(kde_samples1, binNum, alpha=0.5, label='samples from KDE')
    ax2.hist(kde_samples2, binNum, alpha=0.5, label='samples from KDE with sekwed dist')
    ax2.legend()
    ax1.set_title('PSNR dist')
    ax2.set_title('sampling dist')

    fig.suptitle('DS4_DS1 PSNR dist')
    plt.show()
$\endgroup$
  • $\begingroup$ Do you want your sample to follow certain PDF of the PSNR? $\endgroup$ – javierazcoiti Jun 7 at 13:05
  • $\begingroup$ Not necessary. What I want is to sample for example 1k images but instead of having 10 images from the low PSNR values, I would like to have double or more based on the sampling parameters I can choose. $\endgroup$ – Feras Jun 7 at 13:09
  • $\begingroup$ Instead of sampling uniformly from all your data, you can sample with other distribution that gives more weight to small values. But this involves an arbitrary decision about how to sample. $\endgroup$ – javierazcoiti Jun 7 at 13:24
  • $\begingroup$ This is what I did in my code. I used the same distribution skewed to the left by value and then I sampled. I'd prefer more if I can change the new distribution further to sample more from the left. $\endgroup$ – Feras Jun 7 at 13:39
  • $\begingroup$ Let's say you have 100k images ordered by PSNR. You can do round(runif(1000)*100000) and select those elements, where every element had the same chance to appear. But you can use other than runif, for example a mixture of uniforms, or a function created by you and sample from it using Monte Carlo. Note: in that use of runif you may obtain a 0, but hope what I try to say helps. $\endgroup$ – javierazcoiti Jun 7 at 13:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.