Thanks very much, not sure how I didn't find that in my searching.
In the meantime it turned out to be quite easy to code it myself, and I ended up knocking up a function which could vary the saturation, rather than just making it greyscale. Here's the code below in case anyone finds it useful.
img is a QImage and v is a float. v=0 will give black and white, v=0.5 will halve the colour saturation. v=2 will double the saturation, but I haven't added any min() or max() in the example so that would need to be added if v>1.
for x in range(0, img.width()):
for y in range(0, img.height()):
c = img.pixel(x, y)
r1, g1, b1 = qRed(c), qGreen(c), qBlue(c)
grey = (r1 + g1 + b1) / 3
r2 = grey + (v * (r1 - grey))
g2 = grey + (v * (g1 - grey))
b2 = grey + (v * (b1 - grey))
img.setPixel(x, y, qRgb(int(r2), int(g2), int(b2)))